﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////
// Служебный модуль предназначен для внутреннего использования
// Основное назначение модуля - поддержка процедур подтверждения операций в сервисе "Облачная подпись"
// Реализовано две схемы: самостоятельная и встраиваемая в существующие формы
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

#Область ДляВызоваИзДругихПодсистем

// Следующие процедуры и функции предназначены для интеграции с 1С-Отчетность

// Формирует фоновое задание для запроса сервера в процессе подтверждения
//
// Параметры:
//  ОповещениеСледующее 	- ОписаниеОповещения - обработчик для получения результатов запроса
//  НастройкиПользователя 	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//   ДанныеПодтверждения	- см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//  ПараметрыОперации 		- Структура, ФиксированнаяСтруктура - позволяет указать дополнительные параметры операции.
//
Процедура ОтправкаЗапроса(ОповещениеСледующее, НастройкиПользователя, ДанныеПодтверждения, ПараметрыОперации = Неопределено) Экспорт
	
	СервисКриптографииDSSСлужебныйКлиент.НачатьЗамерВремени(ДанныеПодтверждения, "ЭтапЦикла");
	
	Если ДанныеПодтверждения.ВерсияПодтверждения = 2  Тогда
		АдресПодключения = СервисКриптографииDSSКлиентСервер.ПолучитьПолеСтруктуры(НастройкиПользователя.Методы, "СервисПодтверждения20", "");
	Иначе
		АдресПодключения = СервисКриптографииDSSКлиентСервер.ПолучитьПолеСтруктуры(НастройкиПользователя.Методы, "СервисПодтверждения", "");
	КонецЕсли;

	Если ЗначениеЗаполнено(АдресПодключения) Тогда
		ПараметрыЗапроса = СервисКриптографииDSSКлиентСервер.ПодготовитьПараметрыОтправкиЗапроса(НастройкиПользователя, ДанныеПодтверждения);
		ПараметрыЗадания = Новый Структура();
		ПараметрыЗадания.Вставить("БазовыйВызов", ДанныеПодтверждения.ТипПодтверждения = "Аутентификация");
		ПараметрыЗадания.Вставить("Подключение", НастройкиПользователя.Подключение);
		ПараметрыЗадания.Вставить("АдресПодключения", АдресПодключения);
		ПараметрыЗадания.Вставить("ПараметрыЗапроса", ПараметрыЗапроса);
		ПараметрыЗадания.Вставить("HTTPМетод", "POST");
		ПараметрыЗадания.Вставить("ТипСодержания", "json");
		ПараметрыЗадания.Вставить("НастройкиПользователя", НастройкиПользователя);
		
		Если ПараметрыОперации = Неопределено Тогда
			ПараметрыОперации = Новый Структура();
		КонецЕсли;
		
		СинхронныйРежим = ПолучитьПолеСтруктуры(ПараметрыОперации, "СинхронныйРежим");
		Если СинхронныйРежим = Неопределено Тогда
			// При подтверждении операций принудительно используем режим фоновых заданий,
			// если иное не задано в параметрах вызова
			ПараметрыОперации.Вставить("СинхронныйРежим", Ложь);
		КонецЕсли;	
		
		НовоеЗадание = СервисКриптографииDSSСлужебныйВызовСервера.ВыполнитьЗапросКСервису(ПараметрыЗадания, ПараметрыОперации);
		
		СервисКриптографииDSSСлужебныйКлиент.ОжидатьЗавершенияВыполненияВФоне(ОповещениеСледующее, НовоеЗадание);
	КонецЕсли;

КонецПроцедуры

// Организует цикл ожидания ввода пользователя и ответа сервиса
//
// Параметры:
//  ОповещениеСледующее 	- ОписаниеОповещения - обработчик для получения результатов запроса
//  РезультатВыполнения		- Структура - ответ сервиса облачной подписи
//  НастройкиПользователя 	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//  ДанныеПодтверждения		- см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//  ФормаВладелец			- ФормаКлиентскогоПриложения - форма владелец
//
Процедура ОбработатьРезультатЗапроса(ОповещениеСледующее, 
										РезультатВыполнения, 
										НастройкиПользователя, 
										ДанныеПодтверждения,
										ФормаВладелец = Неопределено) Экспорт
	
	ТекущийЭтап = ДанныеПодтверждения.ЭтапЦикла;
	
	СервисКриптографииDSSКлиентСервер.РазобратьРезультатЗапроса(РезультатВыполнения, 
					НастройкиПользователя,
					ДанныеПодтверждения,
					СервисКриптографииDSSСлужебныйКлиент.ДатаСеанса());
					
	Если ДанныеПодтверждения.ЭтапЦикла = "Ошибка" Тогда
		ПредставлениеОшибки = НСтр("ru = 'Не выполнен этап:'") + " " + ТекущийЭтап + Символы.ПС
								+ ДанныеПодтверждения.КодОшибки + ": " + ДанныеПодтверждения.Ошибка;
		СервисКриптографииDSSСлужебныйВызовСервера.ЗаписатьОшибкуВЖурналРегистрации(ПредставлениеОшибки);

		ТипОшибки = ПолучитьПолеСтруктуры(РезультатВыполнения, "СтатусОшибки.ИсходныйКод", "");
		РежимПовтора = ТипОшибки = "transaction_pending";

		ОткрытьФормуОшибкиПодтверждения(ОповещениеСледующее, ДанныеПодтверждения, РежимПовтора, ФормаВладелец);
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Ожидание" Тогда
		Если ФормаВладелец <> Неопределено Тогда
			ОтветСервера = СервисКриптографииDSSКлиент.ОтветСервисаПоУмолчанию();
			ОтветСервера.Вставить("НастройкиПользователя", НастройкиПользователя);
			ОтветСервера.Вставить("ДанныеПодтверждения", ДанныеПодтверждения);
			ВыполнитьОбработкуОповещения(ОповещениеСледующее, ОтветСервера);
		Иначе
			ОткрытьФормуПодтвержденияМобильноеПриложение(ОповещениеСледующее, ДанныеПодтверждения, НастройкиПользователя);
		КонецЕсли	
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "ВводКода" Тогда
		Если ФормаВладелец <> Неопределено Тогда
			ОтветСервера = СервисКриптографииDSSКлиент.ОтветСервисаПоУмолчанию();
			ОтветСервера.Вставить("НастройкиПользователя", НастройкиПользователя);
			ОтветСервера.Вставить("ДанныеПодтверждения", ДанныеПодтверждения);
			ВыполнитьОбработкуОповещения(ОповещениеСледующее, ОтветСервера);
		Иначе
			ОткрытьФормуПодтвержденияКода(ОповещениеСледующее, ДанныеПодтверждения, НастройкиПользователя);
		КонецЕсли	
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Предупреждение" Тогда
		ОтветСервера = СервисКриптографииDSSКлиент.ОтветСервисаПоУмолчанию();
		ОтветСервера.Вставить("ДанныеПодтверждения", ДанныеПодтверждения);
		ОтветСервера.Вставить("НастройкиПользователя", НастройкиПользователя);
		ВыполнитьОбработкуОповещения(ОповещениеСледующее, ОтветСервера);
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Окончание" Тогда
		ОтветСервера = СервисКриптографииDSSКлиент.ОтветСервисаПоУмолчанию();
		ОтветСервера.МаркерОбновлен = Истина;
		ОтветСервера.Вставить("ДанныеПодтверждения", ДанныеПодтверждения);
		ОтветСервера.Вставить("НастройкиПользователя", НастройкиПользователя);
		ВыполнитьОбработкуОповещения(ОповещениеСледующее, ОтветСервера);
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Отказ" Тогда
		ОтветСервера = СервисКриптографииDSSКлиент.ОтветСервисаПоУмолчанию();
		ОтветСервера.Вставить("ДанныеПодтверждения", ДанныеПодтверждения);
		ОтветСервера.Вставить("НастройкиПользователя", НастройкиПользователя);
		ВыполнитьОбработкуОповещения(ОповещениеСледующее, ОтветСервера);
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Выбор" Тогда
		Если ДанныеПодтверждения.СписокМетодов.Количество() = 1 Тогда
			ДанныеПодтверждения.ВторичнаяАвторизация = ДанныеПодтверждения.СписокМетодов[0].Идентификатор;
		ИначеЕсли ДанныеПодтверждения.ДоступныеМетоды.Количество() = 1 Тогда
			ДанныеПодтверждения.ВторичнаяАвторизация = ДанныеПодтверждения.ДоступныеМетоды[0];
		КонецЕсли;
		
		Если ЗначениеЗаполнено(ДанныеПодтверждения.ВторичнаяАвторизация) Тогда
			ПараметрыВызова = Новый Структура();
			ПараметрыВызова.Вставить("ОповещениеОЗавершении", ОповещениеСледующее);
			ПараметрыВызова.Вставить("ДанныеПодтверждения", ДанныеПодтверждения);
			ПараметрыВызова.Вставить("НастройкиПользователя", НастройкиПользователя);
			ПараметрыВызова.Вставить("ФормаВладелец", ФормаВладелец);
			ОповещениеСледующее = Новый ОписаниеОповещения("ОтправкаЗапросаПослеВыбораСпособа", ЭтотОбъект, ПараметрыВызова);
			ОтправкаЗапроса(ОповещениеСледующее, НастройкиПользователя, ДанныеПодтверждения)
			
		Иначе
			ОткрытьФормуВыбораСпособа(ОповещениеСледующее, ДанныеПодтверждения, НастройкиПользователя, ФормаВладелец);
			
		КонецЕсли;	
		
	КонецЕсли;

КонецПроцедуры

// Формирует представление оставшегося времени
// 
// Параметры:
//  ВсегоСекунд 	- Число - остаток времени в секундах
//  КороткийФормат 	- Булево - формировать короткое представление
//
// Возвращаемое значение:
//   Строка
//
Функция РазницаФормат(ВсегоСекунд, КороткийФормат = Ложь) Экспорт
	
	КодЯзыка	= СервисКриптографииDSSСлужебныйКлиент.КодЯзыка();
	Результат	= "";
	Часов 		= Цел(ВсегоСекунд / 3600);
	Минут 		= Цел(ВсегоСекунд / 60);
	Секунд 		= ВсегоСекунд % 60;
	
	Если КороткийФормат Тогда
		Если Часов > 0 Тогда
			Результат	= Результат + СокрЛП(Часов) + ":";
		КонецЕсли;
		
		Если Минут > 0 И Часов > 0 Тогда
			Результат	= Результат + Формат(Минут, "ЧЦ=2; ЧН=00; ЧВН=") + ":";
		Иначе	
			Результат	= Результат + Формат(Минут, "ЧЦ=2; ЧН=0") + ":";
		КонецЕсли;
		
		Результат = Результат + Формат(Секунд, "ЧЦ=2; ЧН=00; ЧВН=");
		
		Результат = "(" + Результат + ")";
		
	Иначе	
		Если Часов = 1 Тогда
			Результат	= Результат + Формат(Часов, "ЧЦ=2; ЧН=00;") + " " + НСтр("ru = 'час'", КодЯзыка) + " ";
		ИначеЕсли Часов > 0 Тогда
			Результат	= Результат + Формат(Часов, "ЧЦ=2; ЧН=00;") + " " + НСтр("ru = 'час.'", КодЯзыка) + " ";
		КонецЕсли;
		
		Если Минут > 0 И Часов > 0 Тогда
			Результат	= Результат + Формат(Минут, "ЧЦ=2; ЧН=00; ЧВН=") + " " + НСтр("ru = 'мин.'", КодЯзыка) + " ";
		Иначе	
			Результат	= Результат + Формат(Минут, "ЧЦ=2; ЧН=00") + " " + НСтр("ru = 'мин.'", КодЯзыка) + " ";
		КонецЕсли;
		
		Если Минут > 0 Тогда
			Результат = Результат + Формат(Секунд, "ЧЦ=2; ЧН=00; ЧВН=") + " " + НСтр("ru = 'сек.'", КодЯзыка);
		Иначе
			Результат = Результат + Формат(Секунд, "ЧЦ=2; ЧН=00") + " " + НСтр("ru = 'сек.'", КодЯзыка);
		КонецЕсли;	
		
		Результат = НСтр("ru = 'Осталось'", КодЯзыка) + " " + Результат;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Формирует список выбора способа подтверждения в зависимости от состояния цикла подтверждения
// 
// Параметры:
//  КонтекстФормы 	- ФормаКлиентскогоПриложения
//  ИмяЭлемента 	- Строка - имя элемента со списком выбора
//
Процедура ФильтроватьСписокСпособов(КонтекстФормы, ИмяЭлемента = "ПодтверждениеСпособПодтверждения") Экспорт

	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
 	ИменаЭлементов = РеестрИмен.ИменаЭлементовФормы;
	НовоеИмя = ПолучитьИмяЭлементаФормы(ИменаЭлементов, ИмяЭлемента);

	ДанныеПодтверждения = ДанныеПодтвержденияИзФормы(КонтекстФормы, РеестрИмен);
	НастройкиПользователя = ПолучитьНастройкиПользователяИзФормы(КонтекстФормы, РеестрИмен);
	
	ЭлементФормы = КонтекстФормы.Элементы[НовоеИмя];
	СписокМетодов = ДанныеПодтверждения.СписокМетодов;
	ЕстьОфлайн = ЗначениеЗаполнено(ДанныеПодтверждения.ГрафическийКод);
	
	СписокВыбора = ЭлементФормы.СписокВыбора;
	СписокВыбора.Очистить();
	
	Если СписокМетодов.Количество() = 0 Тогда
		Для каждого СтрокаКлюча Из ДанныеПодтверждения.ДоступныеМетоды Цикл
			СписокВыбора.Добавить(СтрокаКлюча,
									ПолучитьПредставлениеСпособа(СтрокаКлюча, ДанныеПодтверждения, НастройкиПользователя));
		КонецЦикла;
	Иначе	
		Для каждого СтрокаКлюча Из СписокМетодов Цикл
			Если ДанныеПодтверждения.ДоступныеМетоды.Найти(СтрокаКлюча.Тип) <> Неопределено Тогда
				СписокВыбора.Добавить(СтрокаКлюча.Идентификатор, ПолучитьПредставлениеСпособа(СтрокаКлюча, ДанныеПодтверждения, НастройкиПользователя));
			КонецЕсли;	
		КонецЦикла;
	КонецЕсли;	
	
	Если ЕстьОфлайн Тогда
		ОписаниеСпособа = СервисКриптографииDSSКлиентСервер.ПредопределенныйТипАвторизации();
		СписокВыбора.Добавить(ОписаниеСпособа.Тип, 
				ПолучитьПредставлениеСпособа(ОписаниеСпособа.Тип, ДанныеПодтверждения, НастройкиПользователя));
	КонецЕсли;	
	
	Если СписокВыбора.НайтиПоЗначению(ДанныеПодтверждения.ВторичнаяАвторизация) = Неопределено Тогда
		ДанныеПодтверждения.ВторичнаяАвторизация = Неопределено;
	КонецЕсли;
	
	КонтекстФормы[РеестрИмен.СпособПодтверждения] = ДанныеПодтверждения.ВторичнаяАвторизация;
	
	СформироватьПодсказкуСпособовВыбора(КонтекстФормы, ИмяЭлемента);
	
КонецПроцедуры

// Проверяет наличие запущенного цикла подтверждения
//
// Параметры:
//  КонтекстФормы 			- ФормаКлиентскогоПриложения
//  ИсключитьИнициализацию  - Булево
//
// Возвращаемое значение:
//  Булево - если Истина, то процесс подтверждения не окончен
//
Функция ПроверитьЗапущенныйЦиклПодтверждения(КонтекстФормы, ИсключитьИнициализацию = Ложь) Экспорт
	
	Результат = Истина;
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	
	ДанныеПодтверждения = КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
	Если (ДанныеПодтверждения.ЭтапЦикла = "Инициализация" И НЕ ИсключитьИнициализацию)
		ИЛИ ДанныеПодтверждения.ЭтапЦикла = "Окончание"
		ИЛИ ДанныеПодтверждения.ЭтапЦикла = "Ошибка"
		Тогда
		Результат = Ложь;
	КонецЕсли;	
	
	Возврат Результат;
	
КонецФункции

// Подключает обработку ожидания для формы подтверждения.
// Предварительно проверяя состояние формы и объекта подтверждения.
//
// Параметры:
//  КонтекстФормы 			- ФормаКлиентскогоПриложения
//  ВстроенноеПодтверждение	- Булево
//
Процедура ПодключитьОжидание(КонтекстФормы, ВстроенноеПодтверждение = Ложь) Экспорт
	
	Если ПроверитьЗапущенныйЦиклПодтверждения(КонтекстФормы, ВстроенноеПодтверждение)
		И КонтекстФормы.Открыта() Тогда
		КонтекстФормы.ПодключитьОбработчикОжидания("Подключаемый_ПодтверждениеОбработчикОжидания", 1, Истина);
	КонецЕсли;	

КонецПроцедуры

// Получает значение реквизита формы хранящий имена служебных реквизитов для работы с облачной подписи
//
// Параметры:
//  КонтекстФормы 	- ФормаКлиентскогоПриложения
//  ПроверкаНаличия - Булево
// 
// Возвращаемое значение:
//  Структура
//  Неопределено
// 
Функция БазовыйРеестрРеквизитов(КонтекстФормы, ПроверкаНаличия = Ложь) Экспорт
	
	Если ПроверкаНаличия Тогда
		ИщемПоле = Новый Структура(ИмяБазовогоРеквизита());
		ЗаполнитьЗначенияСвойств(ИщемПоле, КонтекстФормы);
		Результат = ИщемПоле[ИмяБазовогоРеквизита()];
	Иначе
		Результат = КонтекстФормы[ИмяБазовогоРеквизита()];
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

#КонецОбласти

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

#Область СамостоятельноеПодтверждение

// Служебная процедура обработки события выбора навигационной ссылки со списком документов
//
Процедура ОбработкаНавигационнойСсылкиДокументов(НавигационнаяСсылка, СтандартнаяОбработка, ФормаВладелец = Неопределено) Экспорт
	
	Если Сред(НавигационнаяСсылка, 1, 5) = "Всего" Тогда
		СтандартнаяОбработка = Ложь;
		ПараметрыФормы = Новый Структура;
		ПараметрыФормы.Вставить("СписокДокументов", ФормаВладелец.ДанныеДокументов.СписокДокументов);
		ОткрытьФормуСпискаФайлов(Неопределено, ПараметрыФормы, ФормаВладелец);
	КонецЕсли;
	
КонецПроцедуры

// Служебная процедура для оформления элемента формы отображающий оставшееся время
//
// Параметры:
//  ЭлементФормы 	- ГруппаФормы
//  ВремяИстекло	- Булево
//
Процедура ОформитьВремяИстекло(ЭлементФормы, ВремяИстекло = Истина) Экспорт
	
	ПустойЦвет 	= Новый Цвет; // установка цвета элемента формы на значение по умолчанию
	ЦветФона	= ?(ВремяИстекло, WebЦвета.ТусклоРозовый, ПустойЦвет);
	ЦветШрифта	= ?(НЕ ВремяИстекло, WebЦвета.Серый, ПустойЦвет);
	ЭлементФормы.ЦветФона = ЦветФона;
	
	Если ЭлементФормы.ПодчиненныеЭлементы.Найти("Осталось") <> Неопределено Тогда
		ЭлементФормы.ПодчиненныеЭлементы.Осталось.ЦветТекста = ЦветШрифта;
	КонецЕсли;	
	
КонецПроцедуры	

// Служебная процедура обработки события смены способа подтверждения из списка выбора
//
// Параметры:
//  КонтекстФормы - ФормаКлиентскогоПриложения - содержит реквизиты:
//    * ДанныеПодтверждения		- см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//    * СпособПодтверждения		- ПеречислениеСсылка.СпособыАвторизацииDSS
//    * НастройкиПользователя	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//
Процедура ПриИзмененииСпособаПодтверждения(КонтекстФормы) Экспорт
	
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	ДанныеПодтверждения = ДанныеПодтвержденияИзФормы(КонтекстФормы, РеестрИмен);
	НастройкиПользователя = КонтекстФормы[РеестрИмен.НастройкиПользователя];
	СпособПодтверждения = КонтекстФормы[РеестрИмен.СпособПодтверждения];
	ТипПодтверждения = СервисКриптографииDSSКлиентСервер.ПолучитьВторичнуюАвторизацию(СпособПодтверждения);
	
	Если ТипПодтверждения = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ОфлайнПодтверждение") Тогда
		ОповещениеСледующее	= КонтекстФормы.ОписаниеОповещенияОЗакрытии;
		КонтекстФормы.ОписаниеОповещенияОЗакрытии = Неопределено;
		ВыполнитьОповещениеФормы(КонтекстФормы, Неопределено, "ПодтверждениеЗакрытьФорму");
		ДанныеПодтверждения.ВторичнаяАвторизация = СпособПодтверждения;
		ДанныеПодтверждения.ЭтапЦикла = "Ожидание";
		ОткрытьФормуОфлайнПодтверждения(ОповещениеСледующее, ДанныеПодтверждения, НастройкиПользователя);

	ИначеЕсли (ТипПодтверждения = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_МобильноеПриложение")
		ИЛИ ТипПодтверждения = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_DSSSDK"))
		И ДанныеПодтверждения.ВторичнаяАвторизация = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ОфлайнПодтверждение") Тогда
		ОповещениеСледующее	= КонтекстФормы.ОписаниеОповещенияОЗакрытии;
		КонтекстФормы.ОписаниеОповещенияОЗакрытии = Неопределено;
		ВыполнитьОповещениеФормы(КонтекстФормы, Неопределено, "ПодтверждениеЗакрытьФорму");
		ДанныеПодтверждения.ВторичнаяАвторизация = СпособПодтверждения;
		ДанныеПодтверждения.ЭтапЦикла = "Ожидание";
		ОткрытьФормуПодтвержденияМобильноеПриложение(ОповещениеСледующее, ДанныеПодтверждения, НастройкиПользователя);
		
	ИначеЕсли СпособПодтверждения <> ДанныеПодтверждения.ВторичнаяАвторизация Тогда
		Если ДанныеПодтверждения.ЭтапЦикла <> "Выбор" Тогда
			ДанныеПодтверждения.ЭтапЦикла = "Начало";
		КонецЕсли;
		ДанныеПодтверждения.Идентификатор = ДанныеПодтверждения.ИдентификаторТранзакции;
		ДанныеПодтверждения.ВторичнаяАвторизация = СпособПодтверждения;
		
		ОтветПользователя = СервисКриптографииDSSКлиент.ОтветСервисаПоУмолчанию();
		ОтветПользователя.Вставить("НастройкиПользователя", НастройкиПользователя);
		ОтветПользователя.Вставить("ДанныеПодтверждения", ДанныеПодтверждения);
		ВыполнитьОповещениеФормы(КонтекстФормы, ОтветПользователя, "ПодтверждениеЗакрытьФорму");
		
	КонецЕсли;	
	
КонецПроцедуры	

// Служебная процедура для асинхронной обработки результата ответа сервиса после выбора способа подтверждения
//
Процедура ОтправкаЗапросаПослеВыбораСпособа(РезультатВызова, ДополнительныеПараметры) Экспорт
	
	НастройкиПользователя	= ДополнительныеПараметры.НастройкиПользователя;
	ДанныеПодтверждения		= ДополнительныеПараметры.ДанныеПодтверждения;
	ОповещениеСледующее		= ДополнительныеПараметры.ОповещениеОЗавершении;
	ФормаВладелец			= ДополнительныеПараметры.ФормаВладелец;
	РезультатВыполнения 	= СервисКриптографииDSSСлужебныйКлиент.ПолучитьРезультатВыполненияВФоне(РезультатВызова, ДанныеПодтверждения);
	
	ОбработатьРезультатЗапроса(
					ОповещениеСледующее, 
					РезультатВыполнения,
					НастройкиПользователя,
					ДанныеПодтверждения,
					ФормаВладелец);
	
КонецПроцедуры

#КонецОбласти

#Область ВстроенноеПодтверждение

#Область ПодключаемыеОбработчики

// Служебная, вызывается при событии нажатия добавленной кнопки
//
// Параметры:
//  КонтекстФормы   	- ФормаКлиентскогоПриложения
//  ПолеФормы 			- ПолеФормы
//  ДанныеВыбора		- СписокЗначений
//              		- Неопределено
//  СтандартнаяОбработка- Булево
//
Процедура ПодтверждениеНачалоВыбора(КонтекстФормы, ПолеФормы, ДанныеВыбора, СтандартнаяОбработка) Экспорт
	
	СтандартнаяОбработка = Ложь;
	ИмяЭлемента = ПолеФормы.Имя;
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	ИменаЭлементов = РеестрИмен.ИменаЭлементовФормы;
	
	Если ИмяЭлемента = ПолучитьИмяЭлементаФормы(ИменаЭлементов, "ПодтверждениеПредставлениеСертификата") Тогда
		ОписаниеСледующее 	= Новый ОписаниеОповещения("ВыбратьСертификатАвторизацииПослеПолучения", ЭтотОбъект, КонтекстФормы);
		ПараметрыОперации	= СервисКриптографииDSSСлужебныйКлиент.ПодготовитьПараметрыОперации();
		СервисКриптографииDSSКлиент.ЗагрузитьДанныеИзФайла(ОписаниеСледующее, ".pfx", , Истина, ПараметрыОперации);
	КонецЕсли;	
	
КонецПроцедуры	

// Служебная, вызывается при событии нажатия добавленной кнопки
//
// Параметры:
//  КонтекстФормы   			- ФормаКлиентскогоПриложения:
//    * ДанныеПодтверждения		- см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//    * НастройкиПользователя	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//  Команда 					- КомандаФормы
//  ОписаниеДанных				- Структура
//  ЗначениеПароля				- Строка
//
// Возвращаемое значение:
//  Булево
//
Функция ПодтверждениеОбработкаКоманды(КонтекстФормы, Команда, ОписаниеДанных, ЗначениеПароля) Экспорт
	
	ОбновитьФорму = Ложь;
	ИмяКоманды = Команда.Имя;
	
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	ИменаЭлементов = РеестрИмен.ИменаЭлементовФормы;
	ДанныеПодтверждения = ДанныеПодтвержденияИзФормы(КонтекстФормы, РеестрИмен); 
	НастройкиПользователя = ПолучитьНастройкиПользователяИзФормы(КонтекстФормы, РеестрИмен);
	
	Если ИмяКоманды = ПолучитьИмяЭлементаФормы(ИменаЭлементов, "ПодтверждениеОК") Тогда
		ДанныеПодтверждения.ЭтапЦикла = "ВводКодаПользователем";
		ДанныеПодтверждения.КодПользователя = КонтекстФормы[РеестрИмен.КодПодтверждения];
		ПодтверждениеОбработатьЭтапЦикла(КонтекстФормы, ОписаниеДанных, ЗначениеПароля);
		УправлениеЭлементамиОбщее(КонтекстФормы, 1);
		
	ИначеЕсли ИмяКоманды = ПолучитьИмяЭлементаФормы(ИменаЭлементов, "ПодтверждениеПовторить") Тогда
		ДанныеПодтверждения.Идентификатор = ДанныеПодтверждения.ИдентификаторТранзакции;
		ДанныеПодтверждения.ЭтапЦикла = "Начало";
		ПодтверждениеОбработатьЭтапЦикла(КонтекстФормы, ОписаниеДанных, ЗначениеПароля);
		УправлениеЭлементамиОбщее(КонтекстФормы, 2);
		
	ИначеЕсли ИмяКоманды = ПолучитьИмяЭлементаФормы(ИменаЭлементов, "ПодтверждениеАвторизация") Тогда
		ПараметрыОперации = Новый Структура("КонтекстФормы", КонтекстФормы);
		ОбработкаСледующая = Новый ОписаниеОповещения("ПодтверждениеРезультатАвторизации", ЭтотОбъект, ПараметрыОперации);
		СервисКриптографииDSSКлиент.ПроверкаАутентификацииПользователя(ОбработкаСледующая, НастройкиПользователя.Ссылка);
		
	ИначеЕсли ИмяКоманды = ПолучитьИмяЭлементаФормы(ИменаЭлементов, "ПодтверждениеПомощь") Тогда
		КонтекстФормы.ОткрытьСправкуФормы();
		
	КонецЕсли;	
	
	Возврат ОбновитьФорму;
	
КонецФункции	

// Служебная, вызывается при событии изменении пользователем реквизитов формы (не только добавленных)
//
// Параметры:
//  КонтекстФормы   			- ФормаКлиентскогоПриложения - содержит реквизиты:
//    * ДанныеПодтверждения		- см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//    * НастройкиПользователя	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//    * ПарольЛогина			- Строка
//    * СпособПодтверждения	- ПеречислениеСсылка.СпособыАвторизацииDSS
//  ПолеФормы 					- ПолеФормы
//  ОписаниеДанных				- Структура
//  ЗначениеПароля				- Строка
//
// Возвращаемое значение:
//  Булево
//
Функция ПодтверждениеПриИзменении(КонтекстФормы, ПолеФормы, ОписаниеДанных, ЗначениеПароля) Экспорт
	
	ИмяЭлемента = ПолеФормы.Имя;
	ОбновитьФорму = Ложь;
	АктивизироватьПоле = Ложь;
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	ИменаЭлементов = РеестрИмен.ИменаЭлементовФормы;
	
	Если ИмяЭлемента = ПолучитьИмяЭлементаФормы(ИменаЭлементов, "ПодтверждениеПароль") Тогда
		КонтекстФормы[РеестрИмен.ПарольЛогина] = СервисКриптографииDSSКлиентСервер.ЗакрытьСекретПользователя(
					КонтекстФормы[РеестрИмен.ПарольЛогина], КонтекстФормы[РеестрИмен.НастройкиПользователя].АвторизованныйПользователь);
		
	ИначеЕсли ИмяЭлемента = "Сертификат" Тогда
		ПодключитьОжидание(КонтекстФормы, Истина);
		ОбновитьФорму = Истина;
		
	ИначеЕсли ИмяЭлемента = ПолучитьИмяЭлементаФормы(ИменаЭлементов, "ПодтверждениеСпособПодтверждения") Тогда
		ДанныеПодтверждения = ДанныеПодтвержденияИзФормы(КонтекстФормы, РеестрИмен); 
		ОбновитьФорму = Истина;
		
		Если ДанныеПодтверждения.ЭтапЦикла = "Инициализация" Тогда
			ОбновитьФорму = НЕ ЗначениеЗаполнено(ДанныеПодтверждения.ВторичнаяАвторизация);
			КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ВторичнаяАвторизация = КонтекстФормы[РеестрИмен.СпособПодтверждения];
			
		ИначеЕсли СервисКриптографииDSSКлиентСервер.ПолучитьВторичнуюАвторизацию(КонтекстФормы[РеестрИмен.СпособПодтверждения]) = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ОфлайнПодтверждение") Тогда
			КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ЭтапЦикла = "ВводКода";
			КонтекстФормы[РеестрИмен.ГрафическийКод] = ПоместитьВоВременноеХранилище(ДанныеПодтверждения.ГрафическийКод, КонтекстФормы.УникальныйИдентификатор);
			КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ГрафическийКодВладелец = КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ВторичнаяАвторизация;
			КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ВторичнаяАвторизация = КонтекстФормы[РеестрИмен.СпособПодтверждения];
			АктивизироватьПоле = Истина;

		ИначеЕсли СервисКриптографииDSSКлиентСервер.ЭтоМобильноеПриложениеДляПодтверждения(КонтекстФормы[РеестрИмен.СпособПодтверждения])
			И ДанныеПодтверждения.ВторичнаяАвторизация = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ОфлайнПодтверждение") Тогда
			Если КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ГрафическийКодВладелец = КонтекстФормы[РеестрИмен.СпособПодтверждения] Тогда
				КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ВторичнаяАвторизация = КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ГрафическийКодВладелец;
				КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ЭтапЦикла = "Ожидание";
			Иначе
				КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ВторичнаяАвторизация = КонтекстФормы[РеестрИмен.СпособПодтверждения];
				КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ГрафическийКод = "";
				КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ГрафическийКодВладелец = Неопределено;
				КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ЭтапЦикла = "Начало";
			КонецЕсли;
			
		Иначе
			Если КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ЭтапЦикла <> "Выбор" Тогда
				КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ЭтапЦикла = "Начало";
				КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Ложь;
			КонецЕсли;
			ДанныеПодтверждения.Идентификатор = ДанныеПодтверждения.ИдентификаторТранзакции;
			ДанныеПодтверждения.ВторичнаяАвторизация = КонтекстФормы[РеестрИмен.СпособПодтверждения];
			ПодтверждениеОбработатьЭтапЦикла(КонтекстФормы, ОписаниеДанных, ЗначениеПароля);
			
		КонецЕсли;
		
		СформироватьПодсказкуСпособовВыбора(КонтекстФормы, ИмяЭлемента);
		
	ИначеЕсли ИмяЭлемента = ПолучитьИмяЭлементаФормы(ИменаЭлементов, "ПодтверждениеЗапомнитьПарольЛогина") Тогда
		КонтекстФормы[РеестрИмен.НастройкиПользователя].ЗапоминатьПароли = КонтекстФормы[РеестрИмен.ЗапомнитьПарольЛогина];
		СервисКриптографииDSSСлужебныйВызовСервера.ОбновитьНастройкиПользователя(
					КонтекстФормы[РеестрИмен.НастройкиПользователя], КонтекстФормы[РеестрИмен.НастройкиПользователя]);
		
	КонецЕсли;
	
	Если ОбновитьФорму Тогда
		УправлениеЭлементамиОбщее(КонтекстФормы, 3);
	КонецЕсли;	

	Если АктивизироватьПоле Тогда
		АктивизироватьПолеФормыПодтверждения(КонтекстФормы, "Выбор");
	КонецЕсли;
		
	Возврат ОбновитьФорму;
	
КонецФункции

// Служебная, вызывается при событии выбора навигационной ссылки
//
// Возвращаемое значение:
//  Булево
//
Функция ПодтверждениеОбработкаНавигационнойСсылки(КонтекстФормы, Элемент, НавигационнаяСсылкаФорматированнойСтроки, СтандартнаяОбработка) Экспорт
	
	ОбновитьФорму = Ложь;
	
	Возврат ОбновитьФорму;
	
КонецФункции

// Служебная, вызывается событии подключенной обработки ожидания
//
// Параметры:
//  КонтекстФормы   			- ФормаКлиентскогоПриложения - содержит реквизиты:
//    * ДанныеПодтверждения	- см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//    * НастройкиПользователя	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//    * СпособПодтверждения	- ПеречислениеСсылка.СпособыАвторизацииDSS
//    * ДанныеСертификата		- Структура
//    * ПодтверждениеТипОперации - Строка
//    * ОжидатьВыполнения		- Булево
//  ОписаниеДанных				- Структура
//  ЗначениеПароля				- Строка
//
Процедура ПодтверждениеОбработкаОжидания(КонтекстФормы, ОписаниеДанных, ЗначениеПароля) Экспорт
	
	ОблачныйСертификат = ЭтоОперацияОблачнойПодписи(КонтекстФормы);
	
	Если НЕ ОблачныйСертификат Тогда
		Возврат;
	КонецЕсли;
	
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	ИменаЭлементов = РеестрИмен.ИменаЭлементовФормы;
	
	АктуальноеВремя = СервисКриптографииDSSСлужебныйКлиент.ДатаСеанса();
	ДанныеПодтверждения = КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
	ТипОперации = КонтекстФормы[РеестрИмен.ПодтверждениеТипОперации];
	НастройкиПользователя = КонтекстФормы[РеестрИмен.НастройкиПользователя];
	
	Если ДанныеПодтверждения.ОбновитьРазмерыФормы Тогда
		КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ОбновитьРазмерыФормы = Ложь;
		АктивизироватьПолеФормыПодтверждения(КонтекстФормы, "Инициализация");
	КонецЕсли;
	
	ПроверитьСервер = ДанныеПодтверждения.ЭтапЦикла = "Ожидание" 
				ИЛИ (ДанныеПодтверждения.ЭтапЦикла = "ВводКода"
				И ЗначениеЗаполнено(ДанныеПодтверждения.ВторичнаяАвторизация)
				И СервисКриптографииDSSКлиентСервер.ПолучитьВторичнуюАвторизацию(ДанныеПодтверждения.ВторичнаяАвторизация) = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ОфлайнПодтверждение"));
	
	Разница = 0;
	Если ЗначениеЗаполнено(ДанныеПодтверждения.СрокДействия) Тогда
		Разница = ДанныеПодтверждения.СрокДействия - АктуальноеВремя;
	КонецЕсли;
	
	МобильныйКлиент = Ложь;
	#Если МобильныйКлиент Тогда
		МобильныйКлиент = Истина;
	#КонецЕсли
	
	Если ДанныеПодтверждения.ЭтапЦикла = "ВводКода" И НЕ МобильныйКлиент Тогда
		ЭлементыФормы = КонтекстФормы.Элементы;
		НовыйЗаголовок = ЭлементыФормы[ПолучитьИмяЭлементаФормы(ИменаЭлементов, "ПодтверждениеОК")].Заголовок;
		УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеОК", "Заголовок",
				ПодтверждениеОтобразитьОсталось(ДанныеПодтверждения, НовыйЗаголовок), ИменаЭлементов);
	КонецЕсли;	

	Разница = АктуальноеВремя - ДанныеПодтверждения.СрокОпроса;
	Если ПроверитьСервер И Разница >= ДанныеПодтверждения.ПериодОпроса Тогда
		ПодтверждениеОбработатьЭтапЦикла(КонтекстФормы, ОписаниеДанных, ЗначениеПароля, Истина);
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Начало" И НЕ КонтекстФормы[РеестрИмен.ОжидатьВыполнения] Тогда
		ПодтверждениеОбработатьЭтапЦикла(КонтекстФормы, ОписаниеДанных, ЗначениеПароля);
		УправлениеЭлементамиОбщее(КонтекстФормы, 4);
	КонецЕсли;	
	
	КлючДействия = КлючДействияОперации(ТипОперации, НастройкиПользователя, ДанныеПодтверждения);

	Если КлючДействия.Подтверждать Тогда
		ПодключитьОжидание(КонтекстФормы, Истина);
	КонецЕсли;	
	
КонецПроцедуры	

// Служебная, вызывается при событии открытия формы
//
Процедура ПодтверждениеПриОткрытии(КонтекстФормы, Отказ = Ложь, ПарольУстановлен = Ложь, ОписаниеДанных = Неопределено) Экспорт
	
	Если НЕ Отказ Тогда
		РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
		ТипОперации = КонтекстФормы[РеестрИмен.ПодтверждениеТипОперации];
		
		ОблачныйСертификат = ЭтоОперацияОблачнойПодписи(КонтекстФормы);
		ДанныеПодтверждения = КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
		Если ЗначениеЗаполнено(ДанныеПодтверждения) Тогда
			КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ПараметрыВариантаВстроенного.ПарольВПамяти = ПарольУстановлен;
			ДанныеПодтверждения.ПараметрыВариантаВстроенного.ПакетнаяОперация = ПроверитьПакетнуюОперацию(ТипОперации, ОписаниеДанных, ДанныеПодтверждения);
		КонецЕсли;
		УправлениеЭлементамиОбщее(КонтекстФормы, 5);
		Если ТипОперации <> "Проверка" Тогда
			ФильтроватьСписокСпособов(КонтекстФормы);
			Если КонтекстФормы.Открыта() И ОблачныйСертификат Тогда
				ПодключитьОжидание(КонтекстФормы, Истина);
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;	
	
КонецПроцедуры

// Служебная, асинхронное продолжение обработки в ПодтверждениеОбработкаКоманды.
// Применяется в случае отдельной авторизации пользователей: двухфакторная и веб-форма.
// 
Процедура ПодтверждениеРезультатАвторизации(РезультатВыполнения, ВходящийКонтекст) Экспорт
	
	КонтекстФормы = ВходящийКонтекст.КонтекстФормы;
	
	Если ПроверитьКонтекстФормы(КонтекстФормы) И РезультатВыполнения.Выполнено Тогда
		РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
		КонтекстФормы[РеестрИмен.НастройкиПользователя] = РезультатВыполнения.НастройкиПользователя;
		УправлениеЭлементамиОбщее(КонтекстФормы, 6);
		ВыполнитьОповещениеФормы(КонтекстФормы, Истина, "ПодтверждениеАвторизация");
	КонецЕсли;	
	
КонецПроцедуры

#КонецОбласти

#Область Прочее

// Служебная, проверяет необходимость интерактивного взаимодействия с пользователем.
// В этом случае форма отображается пользователю, вне зависимости от параметров операции.
//
// Возвращаемое значение:
//  Булево
//
Функция ОблачнаяПодписьТребуетПодтверждения(КонтекстФормы, УчетАвторизации = Ложь) Экспорт
	
	Результат = Ложь;
	
	Если ЭтоОперацияОблачнойПодписи(КонтекстФормы) Тогда
		РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
		ТипОперации = КонтекстФормы[РеестрИмен.ПодтверждениеТипОперации];
		НастройкиПользователя = КонтекстФормы[РеестрИмен.НастройкиПользователя];
		ДанныеПодтверждения = КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
		ДатаСеанса		= СервисКриптографииDSSСлужебныйКлиент.ДатаСеанса();
		Авторизован		= СервисКриптографииDSSКлиентСервер.УчетнаяЗаписьАвторизована(НастройкиПользователя, ДатаСеанса);
		КлючДействия 	= КлючДействияОперации(ТипОперации, НастройкиПользователя, ДанныеПодтверждения);
		ТребуетПинКод	= ТипОперации <> "Шифрование";
		
		Если Авторизован И ТипОперации <> "Шифрование" Тогда
			ТекущийСертификат = ДанныеПодтверждения.Сертификат;
			ТребуетПинКод = ТекущийСертификат.ТребуетсяПинКод И НЕ ЗначениеЗаполнено(ТекущийСертификат.ПинКод);
		КонецЕсли;
		
		Если УчетАвторизации Тогда
			Результат = Авторизован И КлючДействия.Подтверждать;
		Иначе	
			Результат = ТребуетПинКод ИЛИ НЕ Авторизован ИЛИ КлючДействия.Подтверждать;
		КонецЕсли;	
		
	КонецЕсли;	
		
	Возврат Результат;
	
КонецФункции	

// Служебная, отображает ошибку, в результате выбора сертификата
//
Процедура ПроверитьНаОшибкуСертификата(КонтекстФормы) Экспорт

	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	
	Если ЗначениеЗаполнено(КонтекстФормы.Сертификат)
		И ЗначениеЗаполнено(КонтекстФормы[РеестрИмен.ДанныеСертификата]) Тогда
		
		Если ЗначениеЗаполнено(КонтекстФормы[РеестрИмен.ДанныеСертификата].Ошибка) Тогда
			СервисКриптографииDSSКлиент.ВывестиОшибку(Неопределено, КонтекстФормы[РеестрИмен.ДанныеСертификата].Ошибка);
		КонецЕсли;	
		
	КонецЕсли;

КонецПроцедуры

// Служебная, общая процедура позволяющая проверить тип операции по типу сертификата
//
// Возвращаемое значение:
//  Булево
//
Функция ЭтоОперацияОблачнойПодписи(КонтекстФормы) Экспорт
	
	Результат = Ложь;
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	ДанныеСертификата = КонтекстФормы[РеестрИмен.ДанныеСертификата];
	Если ЗначениеЗаполнено(ДанныеСертификата) Тогда
		Результат = СервисКриптографииDSSКлиентСервер.ПолучитьПолеСтруктуры(ДанныеСертификата, "Облачный", Ложь);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Служебная, проверяет возможность отправки запроса на сервис облачной подписи в момент открытия формы.
//
// Возвращаемое значение:
//  Булево
//
Функция ПроверкаВыполненияНачальнойОперации(КонтекстФормы, БезПодтверждения = Неопределено) Экспорт
	
	Результат = Ложь;
	
	Если ЭтоОперацияОблачнойПодписи(КонтекстФормы) Тогда
		Если БезПодтверждения = Неопределено Тогда
			Результат = ОблачнаяПодписьТребуетПодтверждения(КонтекстФормы);
		ИначеЕсли БезПодтверждения Тогда
			Результат = ОблачнаяПодписьТребуетПодтверждения(КонтекстФормы, Истина);
		Иначе
			Результат = Ложь;
		КонецЕсли;	
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Служебная, используется при интерактивном нажатии кнопки основного действия.
// В случае обнаружения ошибок выдает сообщения о ней.
// Проверяется наличие пин-кода и способа подтверждения.
//
// Возвращаемое значение:
//  Булево
//
Функция ПроверкаПередВыполнениемОперации(КонтекстФормы, ЗначениеПароля) Экспорт
	
	Результат = Истина;
	
	Если ЭтоОперацияОблачнойПодписи(КонтекстФормы) Тогда
		ТекстОшибки = "";
		КодЯзыка = СервисКриптографииDSSСлужебныйКлиент.КодЯзыка();
		РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
		
		ТипОперации = КонтекстФормы[РеестрИмен.ПодтверждениеТипОперации];
		НастройкиПользователя = КонтекстФормы[РеестрИмен.НастройкиПользователя];
		СертификатАвторизации = НастройкиПользователя.СертификатАвторизации ИЛИ НастройкиПользователя.ПервичнаяАутентификация <> ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Первичный_СертификатАвторизации");
		ДатаСеанса = СервисКриптографииDSSСлужебныйКлиент.ДатаСеанса();
		ДанныеПодтверждения = КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
		Авторизован	= СервисКриптографииDSSКлиентСервер.УчетнаяЗаписьАвторизована(НастройкиПользователя, ДатаСеанса);
		КлючДействия = КлючДействияОперации(ТипОперации, НастройкиПользователя, ДанныеПодтверждения);
		ТребуетПинКод = ТипОперации <> "Шифрование";
		ВыбранСпособ = Истина;
		
		Если ТипОперации <> "Шифрование" И ТипОперации <> "Проверка" Тогда
			ВыбранСпособ = ЗначениеЗаполнено(ДанныеПодтверждения.ВторичнаяАвторизация);
		КонецЕсли;	
		
		Если Авторизован И ТипОперации <> "Шифрование" Тогда
			ТекущийСертификат = ДанныеПодтверждения.Сертификат;
			ТребуетПинКод = ТекущийСертификат.ТребуетсяПинКод И НЕ ЗначениеЗаполнено(ЗначениеПароля);
		КонецЕсли;
		
		Если КлючДействия.Подтверждать И НЕ ВыбранСпособ Тогда
			ТекстОшибки = ТекстОшибки + Символы.ПС + НСтр("ru = 'Не указан способ подтверждения'", КодЯзыка);
		КонецЕсли;
		
		Если ТребуетПинКод И Авторизован Тогда
			ТекстОшибки = ТекстОшибки + Символы.ПС + НСтр("ru = 'Не указан пин-код к закрытому ключу сертификата'", КодЯзыка);
		КонецЕсли;
		
		Если НЕ Авторизован 
			И НЕ СертификатАвторизации 
			И НЕ ЗначениеЗаполнено(КонтекстФормы[РеестрИмен.ПодтверждениеДанныеСертификата]) Тогда
			ТекстОшибки = ТекстОшибки + Символы.ПС + НСтр("ru = 'Необходимо загрузить сертификат авторизации.'", КодЯзыка);
		КонецЕсли;
		
		Если НЕ ПустаяСтрока(ТекстОшибки) Тогда
			Результат = Ложь;
			СервисКриптографииDSSКлиент.ВывестиОшибку(Неопределено, СокрЛП(ТекстОшибки));
		КонецЕсли;	
			
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Служебная, формирует параметры запроса для отправки на сервис облачной подписи, и по необходимости 
// вторичной авторизации и начало цикла подтверждения.
//
// Параметры:
//  КонтекстФормы   			- ФормаКлиентскогоПриложения - содержит реквизиты:
//    * ДанныеПодтверждения	- см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//    * НастройкиПользователя	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//    * ПарольЛогина			- Строка
//    * СпособПодтверждения	- ПеречислениеСсылка.СпособыАвторизацииDSS
//    * ДанныеСертификата		- Структура
//    * ПодтверждениеТипОперации - Строка
//    * ОжидатьВыполнения		- Булево
//    * КодПодтверждения		- Строка
//  ОписаниеДанных				- Структура
//  ЗначениеПароля				- Строка
//  Индекс						- Число - элемент данных для обработки
//
Процедура ВыполнитьНачальнуюОперациюСервиса(
					КонтекстФормы,
					ОписаниеДанных = Неопределено, 
					ЗначениеПароля = "", 
					Индекс = 0) Экспорт
	
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	НастройкиПользователя = ПолучитьНастройкиПользователяИзФормы(КонтекстФормы, РеестрИмен);
	ТипОперации = КонтекстФормы[РеестрИмен.ПодтверждениеТипОперации];
	КонтекстФормы[РеестрИмен.КодПодтверждения] = "";
	ПарольПользователя = Неопределено;
	Если ТипОперации <> "Проверка" Тогда
		Если ЗначениеЗаполнено(КонтекстФормы[РеестрИмен.ПарольЛогина]) Тогда
			ПарольПользователя = СервисКриптографииDSSКлиентСервер.ОбъектПароля(КонтекстФормы[РеестрИмен.ПарольЛогина], 1);
		Иначе	
			ПарольПользователя = СервисКриптографииDSSКлиент.ПодготовитьОбъектПароля("");
		КонецЕсли;	
	КонецЕсли;	
	ДатаСеанса = СервисКриптографииDSSСлужебныйКлиент.ДатаСеанса();
	Авторизован	= СервисКриптографииDSSКлиентСервер.УчетнаяЗаписьАвторизована(НастройкиПользователя, ДатаСеанса);
	
	ПараметрыОперации = Новый Структура();
	ПараметрыОперации.Вставить("КонтекстФормы", КонтекстФормы);
	ПараметрыОперации.Вставить("ТипОперации", ТипОперации);
	ПараметрыОперации.Вставить("ОписаниеДанных", ОписаниеДанных);
	ПараметрыОперации.Вставить("ЗначениеПароля", ЗначениеПароля);
	ПараметрыОперации.Вставить("Индекс", Индекс);
	
	ОповещениеСледующее = Новый ОписаниеОповещения("ВыполнитьНачальнуюОперациюСервисаПослеАвторизации", ЭтотОбъект, ПараметрыОперации);
	
	Если НЕ Авторизован
		И ТипОперации <> "Аутентификация" 
		И НастройкиПользователя.ПервичнаяАутентификация = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Первичный_ДвухФакторная") Тогда
		ПараметрыОперации = Новый Структура;
		Если ПарольПользователя <> Неопределено Тогда
			ПараметрыОперации.Вставить("ПарольПользователя", ПарольПользователя);
		КонецЕсли;
		Если ЗначениеЗаполнено(НастройкиПользователя.Ссылка) ИЛИ НЕ ЗначениеЗаполнено(НастройкиПользователя.Логин) Тогда
			СервисКриптографииDSSКлиент.ПроверкаАутентификацииПользователя(ОповещениеСледующее, НастройкиПользователя.Ссылка, ПараметрыОперации);
		Иначе
			СервисКриптографииDSSКлиент.ПроверкаАутентификацииПользователя(ОповещениеСледующее, НастройкиПользователя, ПараметрыОперации);
		КонецЕсли;
		
	Иначе
		РезультатВыполнения = СервисКриптографииDSSКлиент.ОтветСервисаПоУмолчанию();
		ВыполнитьОбработкуОповещения(ОповещениеСледующее, РезультатВыполнения);
		
	КонецЕсли;	
	
КонецПроцедуры

#КонецОбласти

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Служебная процедура открывает форму для вывода ошибки возникшей в процессе подтверждения
//
Процедура ОткрытьФормуОшибкиПодтверждения(ОповещениеСледующее, 
			ДанныеПодтверждения, 
			РежимПовторения = Истина, 
			ФормаВладелец = Неопределено)
	
	СервисКриптографииDSSСлужебныйВызовСервера.НачальныеНастройкиФормы("ПодтверждениеОперацииОшибка");
		
	ПараметрыФормы = Новый Структура("ОписаниеОшибки");
	ПараметрыФормы.Вставить("ОписаниеОшибки", ДанныеПодтверждения.Ошибка);
	ПараметрыФормы.Вставить("РежимПовторения", РежимПовторения);
	ПараметрыФормы.Вставить("ДанныеПодтверждения", ДанныеПодтверждения);
	
	ОповещениеОЗавершении = СервисКриптографииDSSСлужебныйКлиент.ОбъектОповещенияОбработкиФормы(ОповещениеСледующее);
	ОткрытьФорму("Обработка.УправлениеПодключениемDSS.Форма.ПодтверждениеОперацииОшибка", ПараметрыФормы, ФормаВладелец, , , , ОповещениеОЗавершении);
	
КонецПроцедуры

// Служебная процедура открывает форму для ввода одноразового пароля, для случаев SMS и EMAIL
//
Процедура ОткрытьФормуПодтвержденияКода(ОповещениеСледующее, ДанныеПодтверждения, НастройкиПользователя)
	
	ПараметрыФормы = Новый Структура();
	ПараметрыФормы.Вставить("ЗаголовокФормы", ДанныеПодтверждения.Заголовок);
	ПараметрыФормы.Вставить("ДанныеДокументов", ДанныеПодтверждения.ДанныеДокументов);
	ПараметрыФормы.Вставить("Сертификат", ДанныеПодтверждения.Сертификат);
	ПараметрыФормы.Вставить("НастройкиПользователя", НастройкиПользователя);
	ПараметрыФормы.Вставить("ДанныеПодтверждения", ДанныеПодтверждения);
	
	ОповещениеОЗавершении = СервисКриптографииDSSСлужебныйКлиент.ОбъектОповещенияОбработкиФормы(ОповещениеСледующее);
	ОткрытьФорму("Обработка.УправлениеПодключениемDSS.Форма.ПодтверждениеОперацииКодПодтверждения", ПараметрыФормы, , , , , ОповещениеОЗавершении);
	
КонецПроцедуры

// Служебная процедура открывает форму для ожидания результата подтверждения от сервиса облачной подписи,
// для случаев мобильных приложений.
//
Процедура ОткрытьФормуПодтвержденияМобильноеПриложение(ОповещениеСледующее, ДанныеПодтверждения, НастройкиПользователя)
	
	ПараметрыФормы = Новый Структура();
	ПараметрыФормы.Вставить("ЗаголовокФормы", ДанныеПодтверждения.Заголовок);
	ПараметрыФормы.Вставить("ДанныеДокументов", ДанныеПодтверждения.ДанныеДокументов);
	ПараметрыФормы.Вставить("Сертификат", ДанныеПодтверждения.Сертификат);
	ПараметрыФормы.Вставить("НастройкиПользователя", НастройкиПользователя);
	ПараметрыФормы.Вставить("ДанныеПодтверждения", ДанныеПодтверждения);
	
	ОповещениеОЗавершении = СервисКриптографииDSSСлужебныйКлиент.ОбъектОповещенияОбработкиФормы(ОповещениеСледующее);
	ОткрытьФорму("Обработка.УправлениеПодключениемDSS.Форма.ПодтверждениеОперацииМобильноеПриложение", ПараметрыФормы, , , , , ОповещениеОЗавершении);
	
КонецПроцедуры

// Служебная процедура открывает форму выбора способа подтверждения.
// Вызывается в начале подтверждения, если учетная запись не содержит соответствующей настройки.
//
Процедура ОткрытьФормуВыбораСпособа(ОповещениеСледующее, ДанныеПодтверждения, НастройкиПользователя, ФормаВладелец = Неопределено)
	
	СписокСпособов = Новый Массив;
	Для каждого СтрокаКлюча Из ДанныеПодтверждения.СписокМетодов Цикл
		СписокСпособов.Добавить(СтрокаКлюча);
	КонецЦикла;
	
	ПараметрыФормы = Новый Структура();
	ПараметрыФормы.Вставить("СписокСпособов", СписокСпособов);
	ПараметрыФормы.Вставить("ДанныеПодтверждения", ДанныеПодтверждения);
	ПараметрыФормы.Вставить("НастройкиПользователя", НастройкиПользователя);
	
	ОповещениеОЗавершении = СервисКриптографииDSSСлужебныйКлиент.ОбъектОповещенияОбработкиФормы(ОповещениеСледующее);
	ОткрытьФорму("Обработка.УправлениеПодключениемDSS.Форма.ПодтверждениеОперацииВыборСпособа", ПараметрыФормы, ФормаВладелец, , , , ОповещениеОЗавершении);
	
КонецПроцедуры

// Служебная процедура открывает форму офлайн подтверждения с помощью мобильного приложения
//
// Параметры:
//  ОповещениеСледующее		- ОписаниеОповещения
//  ДанныеПодтверждения		- см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//  НастройкиПользователя	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//
Процедура ОткрытьФормуОфлайнПодтверждения(ОповещениеСледующее, ДанныеПодтверждения, НастройкиПользователя)
	
	ПараметрыФормы = Новый Структура();
	ПараметрыФормы.Вставить("ЗаголовокФормы", ДанныеПодтверждения.Заголовок); // строка
	ПараметрыФормы.Вставить("ДанныеДокументов", ДанныеПодтверждения.ДанныеДокументов);
	ПараметрыФормы.Вставить("Сертификат", ДанныеПодтверждения.Сертификат);
	ПараметрыФормы.Вставить("НастройкиПользователя", НастройкиПользователя);
	ПараметрыФормы.Вставить("ДанныеПодтверждения", ДанныеПодтверждения);
	
	ОповещениеОЗавершении = СервисКриптографииDSSСлужебныйКлиент.ОбъектОповещенияОбработкиФормы(ОповещениеСледующее);
	ОткрытьФорму("Обработка.УправлениеПодключениемDSS.Форма.ПодтверждениеОперацииОфлайн", ПараметрыФормы, , , , , ОповещениеОЗавершении);
	
КонецПроцедуры

//  Служебная процедура открывает форму списка документов для возможности их просмотра
//
Процедура ОткрытьФормуСпискаФайлов(ОповещениеСледующее, ПараметрыФормы, ВладелецФормы)
	
	ОповещениеОЗавершении = СервисКриптографииDSSСлужебныйКлиент.ОбъектОповещенияОбработкиФормы(ОповещениеСледующее);
	ОткрытьФорму("Обработка.УправлениеПодключениемDSS.Форма.ПодтверждениеОперацииВыборНавигационнойСсылки", ПараметрыФормы, , , , , ОповещениеОЗавершении);
	
КонецПроцедуры

// Функция определяет зарегистрированный адрес электронной почты учетной записи и формирует его представление
//
// Параметры:
//  НастройкиПользователя	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//  КодЯзыка				- Строка - код языка вычисленный в контексте вызова
//	
// Возвращаемое значение:
//   Строка
//
Функция СодержаниеПредставленияТелефона(НастройкиПользователя, КодЯзыка)
	
	Если ЗначениеЗаполнено(НастройкиПользователя.Телефон) Тогда
		Результат = НСтр("ru = 'Одноразовый пароль на'", КодЯзыка) + " "
								+ СервисКриптографииDSSКлиентСервер.ПредставлениеТелефона(НастройкиПользователя.Телефон);
	Иначе
		Результат = НСтр("ru = 'Одноразовый пароль на мобильный телефон'", КодЯзыка);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Функция определяет зарегистрированный телефон учетной записи и формирует его представление
//
// Параметры:
//  НастройкиПользователя	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//  КодЯзыка				- Строка - код языка вычисленный в контексте вызова
//	
// Возвращаемое значение:
//   Строка
//
Функция СодержаниеПредставленияПочты(НастройкиПользователя, КодЯзыка)
	
	Если ЗначениеЗаполнено(НастройкиПользователя.ЭлектроннаяПочта) Тогда
		Результат = НСтр("ru = 'Одноразовый пароль на электронную почту'", КодЯзыка) + " "
									+ СервисКриптографииDSSКлиентСервер.ПредставлениеАдресаПочты(НастройкиПользователя.ЭлектроннаяПочта);
	Иначе
		Результат = НСтр("ru = 'Одноразовый пароль на электронную почту'", КодЯзыка);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Продолжение функции при начале выбора поля сертификата авторизации
//
Процедура ВыбратьСертификатАвторизацииПослеПолучения(РезультатВызова, КонтекстФормы) Экспорт
	
	Если РезультатВызова.Выполнено Тогда
		РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
		КонтекстФормы[РеестрИмен.ПодтверждениеДанныеСертификата] = РезультатВызова.Результат.ДанныеФайла;
		КонтекстФормы[РеестрИмен.ПодтверждениеПредставлениеСертификата] = НСтр("ru = 'Сертификат загружен'", СервисКриптографииDSSСлужебныйКлиент.КодЯзыка());
	КонецЕсли;
	
КонецПроцедуры

// Продолжение функции ВыполнитьНачальнуюОперациюСервиса
//
// Параметры:
//  РезультатВызова			- Структура
//  ВходящийКонтекст		- Структура:
//    * Индекс			- Число
//    * ЗначениеПароля	- Строка
//    * ОписаниеДанных	- Структура
//    * КонтекстФормы		- ФормаКлиентскогоПриложения
//
Процедура ВыполнитьНачальнуюОперациюСервисаПослеАвторизации(РезультатВызова, ВходящийКонтекст) Экспорт
	
	КонтекстФормы = ВходящийКонтекст.КонтекстФормы;
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	
	Если РезультатВызова.Выполнено Тогда
		
		Если РезультатВызова.МаркерОбновлен Тогда
			КонтекстФормы[РеестрИмен.НастройкиПользователя] = РезультатВызова.НастройкиПользователя;
		КонецЕсли;
		
		ДанныеПодтверждения = КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
		ТипОперации = КонтекстФормы[РеестрИмен.ПодтверждениеТипОперации];
		НаборДанных = ПолучитьПолеСтруктуры(ВходящийКонтекст.ОписаниеДанных, "НаборДанных", Неопределено);
		ПакетнаяОперация = ПроверитьПакетнуюОперацию(ТипОперации, ВходящийКонтекст.ОписаниеДанных, ДанныеПодтверждения);
		ДанныеПодтверждения.ПараметрыВариантаВстроенного.ПакетнаяОперация = ПакетнаяОперация;
		
		Если ПакетнаяОперация Тогда
			ПредставлениеДанных = Новый Структура();
			ПредставлениеДанных.Вставить("Расширение", "");
			ПредставлениеДанных.Вставить("Представление", НСтр("ru = 'Список документов'", ДанныеПодтверждения.КодЯзыка));
			ПредставлениеДанных.Вставить("Данные", Новый Массив);
			
			ВходящийКонтекст.Вставить("ПредставлениеДанных", ПредставлениеДанных);
			ВыполнитьНачальнуюОперациюСервисаПодготовитьДанные(0, ВходящийКонтекст);
			
		Иначе
			Если НаборДанных <> Неопределено Тогда
				ТекущийЭлементНабораДанных = НаборДанных[ВходящийКонтекст.Индекс];
			Иначе
				ТекущийЭлементНабораДанных = ВходящийКонтекст.ОписаниеДанных;
			КонецЕсли;
			ПредставлениеДанных = ПолучитьПредставлениеДанных(ТекущийЭлементНабораДанных, ВходящийКонтекст.ОписаниеДанных);
			ВыполнитьНачальнуюОперациюСервисаПослеПодготовкиДанных(ПредставлениеДанных, ВходящийКонтекст);
			
		КонецЕсли;
		
	Иначе
		КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ЭтапЦикла = "Ошибка";
		ПоказатьОшибкуФормыПодтверждения(КонтекстФормы, 
					КонтекстФормы[РеестрИмен.ДанныеПодтверждения],
					РезультатВызова.Ошибка,
					ВходящийКонтекст.ОписаниеДанных,
					ВходящийКонтекст.ЗначениеПароля);
	КонецЕсли;	
	
КонецПроцедуры

// Определяет вид подписания: пакетное или одиночный документ
//
// Параметры:
//  ТипОперации				- Строка - тип операции для которой предназначена форма
//  ОписаниеДанных 			- Структура - служебные данные формы подписания
//  ДанныеПодтверждения		- Структура - описывает данные цикла подтверждения
//	
// Возвращаемое значение:
//  Булево - Истина, если это пакетная операция
//	
Функция ПроверитьПакетнуюОперацию(ТипОперации, ОписаниеДанных, ДанныеПодтверждения)
	
	ПакетнаяОперация = Ложь;
	
	НаборДанных = СервисКриптографииDSSКлиентСервер.ПолучитьПолеСтруктуры(ОписаниеДанных, "НаборДанных", Неопределено);
	Если НаборДанных <> Неопределено Тогда
		ПакетнаяОперация = ТипОперации = "Подписание";
	КонецЕсли;
	
	ДанныеПодтверждения.ПараметрыВариантаВстроенного.ПакетнаяОперация = ПакетнаяОперация;
	
	Возврат ПакетнаяОперация;
	
КонецФункции

// Функция формирования представления элемента формы для выбранного способа подтверждения операции
//
// Параметры:
//  ВторичнаяАвторизация	- Структура, ПеречислениеСсылка - выбранный способ подтверждения
//  ДанныеПодтверждения		- Структура - описывает данные цикла подтверждения
//  НастройкиПользователя	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//	
// Возвращаемое значение:
//  - Строка
//  - ФорматированнаяСтрока
//
Функция ПолучитьПредставлениеСпособа(ВторичнаяАвторизация, ДанныеПодтверждения, НастройкиПользователя)
	
	КодЯзыка = ДанныеПодтверждения.КодЯзыка;
	
	Результат	= "";
	ЭтоСтруктура = ТипЗнч(ВторичнаяАвторизация) = Тип("Структура");
	Если ЭтоСтруктура Тогда
		ТекущийВариант = ВторичнаяАвторизация.Тип;
		ЭтоСтруктура = ЗначениеЗаполнено(ВторичнаяАвторизация.Описание);
	Иначе
		ТекущийВариант = ВторичнаяАвторизация;
	КонецЕсли;
	
	ИмяШрифта = "ВыделенныйЗаголовокПодтвержденияШрифт";
	
	Если ЭтоСтруктура Тогда
		Результат = СтроковыеФункцииКлиент.ФорматированнаяСтрока(ВторичнаяАвторизация.Описание);
		
	ИначеЕсли ТекущийВариант = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_СМС") Тогда
		Результат = СтроковыеФункцииКлиент.ФорматированнаяСтрока(
			СодержаниеПредставленияТелефона(НастройкиПользователя, КодЯзыка));
		
	ИначеЕсли ТекущийВариант = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ЭлектроннаяПочта") Тогда
		Результат = СтроковыеФункцииКлиент.ФорматированнаяСтрока(
			СодержаниеПредставленияПочты(НастройкиПользователя, КодЯзыка));
		
	ИначеЕсли ТекущийВариант = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_МобильноеПриложение") Тогда
		ТекстСообщения = НСтр("ru = 'Мобильное приложение'") + " "
						+ "<span style=""font: %1"">" + "КриптоПро" + " myDSS</span>";
		Результат = СтроковыеФункцииКлиент.ФорматированнаяСтрока(
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщения,
				ИмяШрифта));
		
	ИначеЕсли ТекущийВариант = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_AirKeyLite") Тогда
		ТекстСообщения = НСтр("ru = 'Мобильное приложение'") + " "
						 + "<span style=""font: %1"">" + "AirKey DSS</span>";
		Результат = СтроковыеФункцииКлиент.ФорматированнаяСтрока(
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщения,
				ИмяШрифта));
		
	ИначеЕсли ТекущийВариант = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ОфлайнПодтверждение") Тогда
		Результат = СтроковыеФункцииКлиент.ФорматированнаяСтрока(
			НСтр("ru = 'Офлайн-подтверждение через приложение'", КодЯзыка));
		
	ИначеЕсли ТекущийВариант = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_DSSSDK") Тогда
		ТекстСообщения = НСтр("ru='Мобильное приложение'", КодЯзыка) 
			+ "<span style=""font: ВыделенныйЗаголовокПодтвержденияШрифт""> myDSS 2.0 "
			+ НСтр("ru='или другое'") + "</span>";
		Результат = СтроковыеФункцииКлиент.ФорматированнаяСтрока(
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщения,
				ИмяШрифта));
	
	КонецЕсли;	
	
	Возврат Результат;
	
КонецФункции

// Функция выводит полученную информацию с сервера и оформляет ее в соответствии со этапом цикла
//
// Параметры:
//  КонтекстФормы 		- ФормаКлиентскогоПриложения - форма, содержащая элементы подтверждения
//  ИмяЭлементаФормы 	- Строка - имя оформляемого элемента
//
Процедура ВывестиИнформациюСервера(КонтекстФормы, ИмяЭлементаФормы = "ПодтверждениеИнформацияСервера") Экспорт
	
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	ИменаЭлементов = РеестрИмен.ИменаЭлементовФормы;
	ДанныеПодтверждения	= КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
	
	Если ДанныеПодтверждения.ЭтапЦикла = "Ошибка"
		ИЛИ ДанныеПодтверждения.ЭтапЦикла = "Предупреждение" Тогда
		СтильИнформации = ДанныеПодтверждения.Оформление.ПоясняющийОшибкуТекст;
	Иначе
		СтильИнформации = ДанныеПодтверждения.Оформление.ПодтверждениеОперацииОписаниеЦвет;
	КонецЕсли;
	
	УстановитьСвойствоЭлемента(КонтекстФормы.Элементы, ИмяЭлементаФормы, "ЦветТекста", СтильИнформации, ИменаЭлементов); 
	КонтекстФормы[РеестрИмен.ИнформацияСервера] = ДанныеПодтверждения.ОписаниеПодтверждения;
	
КонецПроцедуры

// Служебная, обрабатывает изменение этапа цикла подтверждения
//
Процедура ПодтверждениеОбработатьЭтапЦикла(КонтекстФормы, ОписаниеДанных, ЗначениеПароля, ОжиданиеОтветаПользователя = Ложь)
	
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	РазрешенЗапросСервера 	= НЕ КонтекстФормы[РеестрИмен.ОжидатьВыполнения];
	
	НастройкиПользователя	= КонтекстФормы[РеестрИмен.НастройкиПользователя];
	ДанныеПодтверждения		= КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
	ВторичнаяАвторизация	= ДанныеПодтверждения.ВторичнаяАвторизация;
	ДатаСеанса 				= СервисКриптографииDSSСлужебныйКлиент.ДатаСеанса();
	
	ПараметрыЦикла = Новый Структура;
	ПараметрыЦикла.Вставить("КонтекстФормы", КонтекстФормы);
	ПараметрыЦикла.Вставить("ОписаниеДанных", ОписаниеДанных);
	ПараметрыЦикла.Вставить("ЗначениеПароля", ЗначениеПароля);
	ПараметрыЦикла.Вставить("ОжиданиеОтветаПользователя", ОжиданиеОтветаПользователя);
	
	ОбработкаЦикла = Новый ОписаниеОповещения("ПодтверждениеОбработатьРезультатЗапроса", ЭтотОбъект, ПараметрыЦикла);
	
	Если ДанныеПодтверждения.ЭтапЦикла = "Ошибка" Тогда
		КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Ложь;
		ПоказатьОшибкуФормыПодтверждения(КонтекстФормы, ДанныеПодтверждения, "", ОписаниеДанных, ЗначениеПароля);
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Предупреждение" Тогда
		ВывестиИнформациюСервера(КонтекстФормы);
		КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ЭтапЦикла = "ВводКода";
		КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Ложь;
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Отказ" Тогда
		КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Ложь;
		КонтекстФормы.Закрыть();
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Окончание" И РазрешенЗапросСервера Тогда
		ПараметрыОтвета = СервисКриптографииDSSКлиент.ОтветСервисаПоУмолчанию();
		КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Истина;
		ВыполнитьОповещениеФормы(КонтекстФормы, ПараметрыОтвета, "ПодтверждениеВыполнитьОсновнуюОперацию");
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Ожидание" И РазрешенЗапросСервера Тогда
		Разница = ДатаСеанса - КонтекстФормы[РеестрИмен.ДанныеПодтверждения].СрокОпроса;
		Если Разница > ДанныеПодтверждения.ПериодОпроса Тогда
			КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Истина;
			КонтекстФормы[РеестрИмен.ДанныеПодтверждения].СрокОпроса = ДатаСеанса;
			ОтправкаЗапроса(ОбработкаЦикла, НастройкиПользователя, ДанныеПодтверждения);
		КонецЕсли;
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "ВводКода" И РазрешенЗапросСервера Тогда
		Если СервисКриптографииDSSКлиентСервер.ПолучитьВторичнуюАвторизацию(ВторичнаяАвторизация) = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ОфлайнПодтверждение") Тогда
			Разница = ДатаСеанса - КонтекстФормы[РеестрИмен.ДанныеПодтверждения].СрокОпроса;
			Если Разница > ДанныеПодтверждения.ПериодОпроса Тогда
				КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Истина;
				КонтекстФормы[РеестрИмен.ДанныеПодтверждения].СрокОпроса = ДатаСеанса;
				ОтправкаЗапроса(ОбработкаЦикла, НастройкиПользователя, ДанныеПодтверждения);
			КонецЕсли;
		КонецЕсли;	
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "ВводКодаПользователем" И РазрешенЗапросСервера Тогда
		ДанныеПодтверждения.ЭтапЦикла = "ВводКода";
		КонтекстФормы[РеестрИмен.ДанныеПодтверждения] = ДанныеПодтверждения;
		КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Истина;
		ОтправкаЗапроса(ОбработкаЦикла, НастройкиПользователя, ДанныеПодтверждения);
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Начало" И РазрешенЗапросСервера Тогда
		КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Истина;
		ВыполнитьНачальнуюОперациюСервиса(КонтекстФормы, ОписаниеДанных, ЗначениеПароля);
		
	ИначеЕсли ДанныеПодтверждения.ЭтапЦикла = "Выбор" И РазрешенЗапросСервера Тогда
		// если выбран способ, то отправка запроса, иначе ждем пользователя
		Если ЗначениеЗаполнено(ДанныеПодтверждения.ВторичнаяАвторизация) Тогда
			КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Истина;
			ОтправкаЗапроса(ОбработкаЦикла, НастройкиПользователя, ДанныеПодтверждения);
		Иначе
			КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Ложь;
			ФильтроватьСписокСпособов(КонтекстФормы);
		КонецЕсли;	
		
	КонецЕсли;

КонецПроцедуры

// Служебная получает описание операции из настроек пользователя 
//
Функция КлючДействияОперации(ТипОперации, НастройкиПользователя, ДанныеПодтверждения)
	
	Если ТипОперации = "Подтверждение" 
		ИЛИ ТипОперации = "Аутентификация" Тогда
		КлючДействия = СервисКриптографииDSSКлиентСервер.СвойствоВыполняемойОперации(НастройкиПользователя, ТипОперации);
		КлючДействия.Подтверждать = Истина;
		
	Иначе	
		Если ТипОперации = "Подписание" Тогда
			Если ДанныеПодтверждения.ВерсияПодтверждения = 2 Тогда
				ВидОперации = "ПодписьДокумента";
			ИначеЕсли ДанныеПодтверждения.ПараметрыВариантаВстроенного.ПакетнаяОперация Тогда
				ВидОперации = "ПодписьПакета";
			Иначе
				ВидОперации = "ПодписьДокумента";
			КонецЕсли;
		ИначеЕсли ТипОперации = "Расшифрование" Тогда
			ВидОперации = "Расшифрование";
		Иначе
			ВидОперации = ТипОперации;
		КонецЕсли;
		
		КлючДействия = СервисКриптографииDSSКлиентСервер.СвойствоВыполняемойОперации(НастройкиПользователя, ВидОперации);
		
	КонецЕсли;	
	
	Возврат КлючДействия;
	
КонецФункции

// Служебная, проверяет возможность выполнения операции для существующей и открытой формы
//
Функция ПроверитьКонтекстФормы(КонтекстФормы)
	
	Результат = Истина;
	
	Если КонтекстФормы = Неопределено ИЛИ НЕ КонтекстФормы.Открыта() Тогда
		Результат = Ложь;
	КонецЕсли;
	
	Возврат Результат;

КонецФункции

// Служебная, формирует представление текущего элемента данных, необходимых для создания транзакции подписания
//
// Параметры:
//  ОписаниеДанных 				- Структура
//  ТекущийЭлементНабораДанных  - Неопределено
//                              - Структура
//
Функция ПолучитьПредставлениеДанных(ТекущийЭлементНабораДанных, ОписаниеДанных)
	
	Расширение = "";
	СписокПредставлений = ПолучитьПолеСтруктуры(ОписаниеДанных, "СписокПредставлений");
	Представление = ПолучитьПолеСтруктуры(ОписаниеДанных, "Представление", "");
	НаборДанных = ПолучитьПолеСтруктуры(ОписаниеДанных, "НаборДанных", Неопределено);
	Результат = Новый Структура;
	Результат.Вставить("Данные", Неопределено);
	
	Если СписокПредставлений <> Неопределено И НаборДанных <> Неопределено Тогда
		НашлиИндекс = НаборДанных.Найти(ТекущийЭлементНабораДанных);
		КоличествоПредставлений = СписокПредставлений.Количество();
		Если КоличествоПредставлений = 1 ИЛИ НашлиИндекс = Неопределено Тогда
			Представление = СписокПредставлений[0].Представление 
							+ ?(НаборДанных.Количество() > 1, " (" + СокрЛП(НашлиИндекс) + ")", "");
		ИначеЕсли КоличествоПредставлений > НашлиИндекс Тогда
			Представление = СписокПредставлений[НашлиИндекс].Представление;
		КонецЕсли;	
	КонецЕсли;	
	
	Если ТекущийЭлементНабораДанных <> Неопределено Тогда
		Если ТекущийЭлементНабораДанных.Свойство("Объект") Тогда
			ДанныеФайла = СервисКриптографииDSSСлужебныйВызовСервера.ЗначенияРеквизитовОбъекта(ТекущийЭлементНабораДанных.Объект, "Расширение");
			Расширение = ДанныеФайла.Расширение; // Строка
			
			Если СписокПредставлений <> Неопределено Тогда
				СписокПредставлений = ОписаниеДанных.СписокПредставлений;
				НашлиСтроку = СписокПредставлений.НайтиПоЗначению(ТекущийЭлементНабораДанных.Объект);
				Представление = НашлиСтроку.Представление
			КонецЕсли;
			
		КонецЕсли;
		Результат.Вставить("Данные", ТекущийЭлементНабораДанных.Данные);
	КонецЕсли;	
	
	Результат.Вставить("Расширение", Расширение);
	Результат.Вставить("Представление", Представление);
	
	Возврат Результат
	
КонецФункции

// Служебная, требуется для обновления размеров формы после открытия формы.
// Используется механизм выключения и включения видимости группы элементов.
//
Процедура ОбновитьРазмерыФормы(КонтекстФормы)

	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	СписокГрупп	= КонтекстФормы[РеестрИмен.ИменаГруппКонтейнера];
	ЭлементыФормы = КонтекстФормы.Элементы;
	
	ИзменитьВидимостьКонтейнеров(СписокГрупп, ЭлементыФормы, Неопределено);
	ИзменитьВидимостьКонтейнеров(СписокГрупп, ЭлементыФормы, Неопределено);

КонецПроцедуры

// Служебная, формирует параметры с данными необходимые для создания транзакции подтверждения.
// Начало цикла получения данных для операций (шифрования, подписание, расшифрование), 
// см. подробнее ВыполнитьНачальнуюОперациюСервиса.
//
// Параметры:
//   ИндексЭлемента				- Число
//  ВходящийКонтекст			- Структура:
//    * Индекс					- Число			
//    * ПредставлениеДанных		- Структура:
//      ** Данные				- Массив из Структура
//		
Процедура ВыполнитьНачальнуюОперациюСервисаПодготовитьДанные(ИндексЭлемента, ВходящийКонтекст)
	
	КонтекстФормы = ВходящийКонтекст.КонтекстФормы;
	ОписаниеДанных = ВходящийКонтекст.ОписаниеДанных;
	
	Если ОписаниеДанных.НаборДанных.Количество() > ИндексЭлемента Тогда
		ЭлементДанных = ОписаниеДанных.НаборДанных[ИндексЭлемента];
		ПредставлениеДанных = ПолучитьПредставлениеДанных(ЭлементДанных, ОписаниеДанных);
		
		НоваяСтрока = Новый Структура();
		НоваяСтрока.Вставить("Содержание", Неопределено);
		НоваяСтрока.Вставить("ИмяДокумента", ПредставлениеДанных.Представление);
		НоваяСтрока.Вставить("ТипДокумента", ПредставлениеДанных.Расширение);
		НоваяСтрока.Вставить("ИсходноеСодержание", "");
				
		ВходящийКонтекст.ПредставлениеДанных.Данные.Добавить(НоваяСтрока);
		ВходящийКонтекст.Индекс = ИндексЭлемента + 1;
	
		ОбработчикСледующий = Новый ОписаниеОповещения("ВыполнитьНачальнуюОперациюСервисаПослеПолученияДанных", ЭтотОбъект, ВходящийКонтекст);
		
		ПараметрыОперации = Новый Структура;
		ПараметрыОперации.Вставить("ОбработчикСледующий", ОбработчикСледующий);
		ПараметрыОперации.Вставить("КонтекстФормы", КонтекстФормы);
		ПараметрыОперации.Вставить("ОписаниеДанных", ВходящийКонтекст.ОписаниеДанных);
		ПараметрыОперации.Вставить("Данные", ЭлементДанных.Данные);
		
		ВыполнитьОповещениеФормы(КонтекстФормы, ПараметрыОперации, "ПодтверждениеПодготовитьДанные");
		
	Иначе
		ВыполнитьНачальнуюОперациюСервисаПослеПодготовкиДанных(ВходящийКонтекст.ПредставлениеДанных, ВходящийКонтекст);
		
	КонецЕсли;	
	
КонецПроцедуры

// Служебная, продолжение цикла формирования параметров с данными необходимые для создания транзакции подтверждения.
// Получение очередной порции данных см.подробнее ВыполнитьНачальнуюОперациюСервиса.
// 
// Параметры:
//  РезультатВыполнения			- Структура
//  ВходящийКонтекст 			- Структура:
//    * Индекс				- Число			
//    * ПредставлениеДанных 	- Структура:
//      ** Данные 			- Массив из Структура
//		
Процедура ВыполнитьНачальнуюОперациюСервисаПослеПолученияДанных(РезультатВыполнения, ВходящийКонтекст) Экспорт
	
	ЭтоXMLDSig 	= (ТипЗнч(РезультатВыполнения) = Тип("Структура") И РезультатВыполнения.Свойство("ПараметрыXMLDSig"));
	ЭтоCMS		= (ТипЗнч(РезультатВыполнения) = Тип("Структура") И РезультатВыполнения.Свойство("ПараметрыCMS"));
	
	Если ТипЗнч(РезультатВыполнения) = Тип("Структура")
		И Не ЭтоXMLDSig
		И Не ЭтоCMS Тогда
		Возврат;
	КонецЕсли;
	
	Количество = ВходящийКонтекст.ПредставлениеДанных.Данные.Количество();
	ВходящийКонтекст.ПредставлениеДанных.Данные[Количество - 1].Содержание = РезультатВыполнения;
	
	ВыполнитьНачальнуюОперациюСервисаПодготовитьДанные(ВходящийКонтекст.Индекс, ВходящийКонтекст);
	
КонецПроцедуры

// Служебная, окончание цикла формирования параметров с данными необходимые для создания транзакции подтверждения.
// Отправляет запрос на сервис, см. подробнее ВыполнитьНачальнуюОперациюСервиса.
// 
// Параметры:
//   ДанныеОперации					- Структура
//   ВходящийКонтекст				- Структура:
//     * КонтекстФормы				- ФормаКлиентскогоПриложения:
//       ** ДанныеСертификата	- Структура:
//         *** Идентификатор	- Строка
//
Процедура ВыполнитьНачальнуюОперациюСервисаПослеПодготовкиДанных(ДанныеОперации, ВходящийКонтекст)
	
	КонтекстФормы = ВходящийКонтекст.КонтекстФормы;
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	ДанныеСертификата = ПолучитьДанныеСертификатаИзФормы(КонтекстФормы, РеестрИмен);	
	
	Если ПроверитьКонтекстФормы(КонтекстФормы) Тогда
		СледующаяОбработка = Новый ОписаниеОповещения("ВыполнитьНачальнуюОперациюСервисаПослеВыполнения", ЭтотОбъект, ВходящийКонтекст);
		
		ПарольПользователя = Неопределено;
		ЗначениеПинКода = ?(ЗначениеЗаполнено(ВходящийКонтекст.ЗначениеПароля), ВходящийКонтекст.ЗначениеПароля, Неопределено);
		Если ВходящийКонтекст.ТипОперации <> "Проверка" Тогда
			Если ЗначениеЗаполнено(КонтекстФормы[РеестрИмен.ПарольЛогина]) Тогда
				ПарольПользователя = СервисКриптографииDSSКлиентСервер.ОбъектПароля(КонтекстФормы[РеестрИмен.ПарольЛогина], 1);
			Иначе	
				ПарольПользователя = СервисКриптографииDSSКлиент.ПодготовитьОбъектПароля("");
			КонецЕсли;	
		КонецЕсли;	
		
		ПараметрыВызова = Новый Структура;
		
		Если ЗначениеЗаполнено(КонтекстФормы[РеестрИмен.ПодтверждениеДанныеСертификата]) Тогда
			ПараметрыВызова.Вставить("СертификатАвторизации", КонтекстФормы[РеестрИмен.ПодтверждениеДанныеСертификата]);
		КонецЕсли;
		
		ПараметрыВызова.Вставить("ТипОперации", ВходящийКонтекст.ТипОперации);
		ПараметрыВызова.Вставить("Сертификат", ДанныеСертификата.Идентификатор);
		ПараметрыВызова.Вставить("ДанныеДокумента", ДанныеОперации.Данные);
		ПараметрыВызова.Вставить("ПарольПользователя", ПарольПользователя);
		ПараметрыВызова.Вставить("ПинКод", СервисКриптографииDSSКлиент.ПодготовитьОбъектПароля(ЗначениеПинКода));
		ПараметрыВызова.Вставить("ТипДокумента", ДанныеОперации.Расширение);
		ПараметрыВызова.Вставить("ОписаниеДокумента", ДанныеОперации.Представление);
		ПараметрыВызова.Вставить("ДанныеПодтверждения", КонтекстФормы[РеестрИмен.ДанныеПодтверждения]);

		КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Истина;
		
		СервисКриптографииDSSКлиент.ПодготовитьТранзакцию(
			СледующаяОбработка,
			КонтекстФормы[РеестрИмен.НастройкиПользователя],
			ПараметрыВызова);
			
		УправлениеЭлементамиОбщее(КонтекстФормы, 7);
	КонецЕсли;	
	
КонецПроцедуры	
	
// Служебная, асинхронная обработка результата первичного запроса сервиса.
// Обработка результат выполнения первичной операции см. подробнее ВыполнитьНачальнуюОперациюСервиса.
// 
Процедура ВыполнитьНачальнуюОперациюСервисаПослеВыполнения(РезультатВыполнения, ВходящийКонтекст) Экспорт
	
	АктивизироватьПоле = Ложь;
	КонтекстФормы = ВходящийКонтекст.КонтекстФормы;
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);

	КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Ложь;
	
	Если НЕ ПроверитьКонтекстФормы(КонтекстФормы) Тогда
		Возврат;
	КонецЕсли;
	
	Если РезультатВыполнения.МаркерОбновлен Тогда
		НастройкиПользователя = РезультатВыполнения.НастройкиПользователя;
		КонтекстФормы[РеестрИмен.НастройкиПользователя] = НастройкиПользователя;
	КонецЕсли;
	
	ДанныеПодтверждения = КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
	
	Если РезультатВыполнения.Выполнено Тогда
		
		ЗначениеПароля = ВходящийКонтекст.ЗначениеПароля;
		НастройкиПользователя = КонтекстФормы[РеестрИмен.НастройкиПользователя];
		
		Если ЗначениеЗаполнено(ЗначениеПароля) Тогда
			ДанныеПодтверждения.ПараметрыВариантаВстроенного.ПинКод = ЗначениеПароля;
			ДанныеПодтверждения.ПараметрыВариантаВстроенного.ПинКодПроверен = Истина;
		КонецЕсли;	
		
		Результат = РезультатВыполнения.Результат;
		
		Если Результат.Подтверждение Тогда
			АктивизироватьПоле = Истина;
			ДанныеПодтверждения = Результат.ДанныеПодтверждения;
			КонтекстФормы[РеестрИмен.ДанныеПодтверждения] = ДанныеПодтверждения;
			ВывестиИнформациюСервера(КонтекстФормы);
			ФильтроватьСписокСпособов(КонтекстФормы);
			ПодтверждениеОбработатьЭтапЦикла(КонтекстФормы, ВходящийКонтекст.ОписаниеДанных, ВходящийКонтекст.ЗначениеПароля);
			ПодключитьОжидание(КонтекстФормы);
		Иначе
			ПакетнаяОперация = ДанныеПодтверждения.ПараметрыВариантаВстроенного.ПакетнаяОперация;
			ПараметрыВыполнения = СервисКриптографииDSSКлиент.ОтветСервисаПоУмолчанию();
			ПараметрыВыполнения.Вставить("ДанныеПакета", Неопределено);
			Если ПакетнаяОперация Тогда
				ПараметрыВыполнения.ДанныеПакета = ВходящийКонтекст.ПредставлениеДанных.Данные;
			КонецЕсли;
			КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Истина;
			ВыполнитьОповещениеФормы(КонтекстФормы, ПараметрыВыполнения, "ПодтверждениеВыполнитьОсновнуюОперацию");
		КонецЕсли;
		УправлениеЭлементамиОбщее(КонтекстФормы, 8);
		
	Иначе
		ДанныеПодтверждения.ЭтапЦикла = "Ошибка";
		ПоказатьОшибкуФормыПодтверждения(КонтекстФормы,
										ДанныеПодтверждения,
										РезультатВыполнения.Ошибка,
										ВходящийКонтекст.ОписаниеДанных,
										ВходящийКонтекст.ЗначениеПароля);
		
	КонецЕсли;	
	
	Если АктивизироватьПоле Тогда
		АктивизироватьПолеФормыПодтверждения(КонтекстФормы, "Начало");
	КонецЕсли;
	
КонецПроцедуры

// Служебная, отображает сообщение об ошибке пользователю и ожидает ответа пользователя
//
Процедура ПоказатьОшибкуФормыПодтверждения(КонтекстФормы, 
									ДанныеПодтверждения, 
									СодержаниеОшибки, 
									ОписаниеДанных = Неопределено, 
									ЗначениеПароля = "")
	
	ПараметрыЦикла = Новый Структура();
	ПараметрыЦикла.Вставить("КонтекстФормы", КонтекстФормы);
	ПараметрыЦикла.Вставить("ОписаниеДанных", ОписаниеДанных);
	ПараметрыЦикла.Вставить("ЗначениеПароля", ЗначениеПароля);
	
	ОбработкаРезультата = Новый ОписаниеОповещения("ПоказатьОшибкуФормыПодтвержденияПослеПоказа", ЭтотОбъект, ПараметрыЦикла);
	
	Если ЗначениеЗаполнено(СодержаниеОшибки) Тогда
		Если НЕ СервисКриптографииDSSКлиентСервер.ЭтоОшибкаОтказа(СодержаниеОшибки) Тогда
			СервисКриптографииDSSКлиент.ВывестиОшибку(ОбработкаРезультата, СодержаниеОшибки);
		КонецЕсли;	
		
	ИначеЕсли ЗначениеЗаполнено(ДанныеПодтверждения.Ошибка) Тогда
		ОткрытьФормуОшибкиПодтверждения(ОбработкаРезультата, ДанныеПодтверждения, Истина, КонтекстФормы);
		
	КонецЕсли;
	
КонецПроцедуры

// Служебная, обрабатывает ответ пользователя: повторить операцию или отказаться
// см. ПоказатьОшибкуФормыПодтверждения
//
Процедура ПоказатьОшибкуФормыПодтвержденияПослеПоказа(РезультатВызова, ВходящийКонтекст) Экспорт
	
	КонтекстФормы = ВходящийКонтекст.КонтекстФормы;
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	
	Если РезультатВызова.Выполнено Тогда
		Если РезультатВызова.Свойство("ДанныеПодтверждения") Тогда
			КонтекстФормы[РеестрИмен.ДанныеПодтверждения] = РезультатВызова.ДанныеПодтверждения;
			Если КонтекстФормы[РеестрИмен.СпособПодтверждения] = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ОфлайнПодтверждение") Тогда
				КонтекстФормы[РеестрИмен.СпособПодтверждения] = КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ГрафическийКодВладелец;
			КонецЕсли;
			ПодтверждениеОбработатьЭтапЦикла(КонтекстФормы, ВходящийКонтекст.ОписаниеДанных, ВходящийКонтекст.ЗначениеПароля);
		КонецЕсли;
		УправлениеЭлементамиОбщее(КонтекстФормы, 9);
		ВыполнитьОповещениеФормы(КонтекстФормы, СервисКриптографииDSSКлиент.ОтветСервисаПоУмолчанию(Ложь), "ПодтверждениеВыполнитьОсновнуюОперацию");
		
	ИначеЕсли КонтекстФормы.Открыта() Тогда
		КонтекстФормы.Закрыть();
		
	КонецЕсли;
	
КонецПроцедуры

// Служебная, посылает оповещение о событии форме для обработки в ее контексте
//
Процедура ВыполнитьОповещениеФормы(КонтекстФормы, РезультатВызова, ИмяСобытия)
	
	Оповестить(ИмяСобытия, РезультатВызова, КонтекстФормы.УникальныйИдентификатор);
	
КонецПроцедуры

// Служебная, асинхронно обрабатывает результат запроса к сервису облачной подписи для встроенного подтверждения
// см. ПодтверждениеОбработатьЭтапЦикла
//
Процедура ПодтверждениеОбработатьРезультатЗапроса(РезультатВыполнения, ВходящийКонтекст) Экспорт
	
	КонтекстФормы = ВходящийКонтекст.КонтекстФормы;
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	
	ОжидатьВыполнения = Ложь;
	Если КонтекстФормы <> Неопределено Тогда
		ОжидатьВыполнения = КонтекстФормы[РеестрИмен.ОжидатьВыполнения];
		КонтекстФормы[РеестрИмен.ОжидатьВыполнения] = Ложь;
	КонецЕсли;	
	
	Если ПроверитьКонтекстФормы(КонтекстФормы) Тогда
		ДанныеПодтверждения = КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
		РезультатВызова	= СервисКриптографииDSSСлужебныйКлиент.ПолучитьРезультатВыполненияВФоне(РезультатВыполнения, ДанныеПодтверждения);
		ЭтапЦикла 		= "";
		
		Если РезультатВызова.Выполнено Тогда
			ЭтапЦикла = ДанныеПодтверждения.ЭтапЦикла;
			СервисКриптографииDSSКлиентСервер.РазобратьРезультатЗапроса(
							РезультатВызова, 
							КонтекстФормы[РеестрИмен.НастройкиПользователя],
							КонтекстФормы[РеестрИмен.ДанныеПодтверждения],
							СервисКриптографииDSSСлужебныйКлиент.ДатаСеанса());
							
			Если КонтекстФормы[РеестрИмен.ДанныеПодтверждения].ЭтапЦикла <> "Ошибка" Тогда
				ФильтроватьСписокСпособов(КонтекстФормы);
			КонецЕсли;
				
			ВывестиИнформациюСервера(КонтекстФормы);
			ПодтверждениеОбработатьЭтапЦикла(КонтекстФормы, ВходящийКонтекст.ОписаниеДанных, ВходящийКонтекст.ЗначениеПароля);
			
		Иначе
			ДанныеПодтверждения.ЭтапЦикла = "Ошибка";
			ПоказатьОшибкуФормыПодтверждения(КонтекстФормы, 
						КонтекстФормы[РеестрИмен.ДанныеПодтверждения],
						РезультатВызова.Ошибка,
						ВходящийКонтекст.ОписаниеДанных,
						ВходящийКонтекст.ЗначениеПароля);
		КонецЕсли;
		
		Если НЕ ВходящийКонтекст.ОжиданиеОтветаПользователя ИЛИ ОжидатьВыполнения Тогда
			УправлениеЭлементамиОбщее(КонтекстФормы, 10);
		КонецЕсли;
		
	Иначе
		СервисКриптографииDSSСлужебныйКлиент.ПолучитьРезультатВыполненияВФоне(РезультатВыполнения, "Ошибка");
	КонецЕсли;	
	
	АктивизироватьПолеФормыПодтверждения(КонтекстФормы, ЭтапЦикла);
	
КонецПроцедуры

// Служебная для обработки элементов формы, активирует поле ввода одноразового пароля после получения ответа от сервиса
//
Процедура АктивизироватьПолеФормыПодтверждения(КонтекстФормы, БылЭтап = "Начало")
	
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	ИменаЭлементов = РеестрИмен.ИменаЭлементовФормы;
	ДанныеПодтверждения = КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
	НастройкиПользователя = КонтекстФормы[РеестрИмен.НастройкиПользователя];
	ТипОперации = КонтекстФормы[РеестрИмен.ПодтверждениеТипОперации];
	ЭлементыФормы = КонтекстФормы.Элементы;
	
	Если БылЭтап = "Инициализация" Тогда
		ОбновитьРазмерыФормы(КонтекстФормы);
		ДатаСеанса = СервисКриптографииDSSСлужебныйКлиент.ДатаСеанса();
		ЕстьАвторизация = СервисКриптографииDSSКлиентСервер.УчетнаяЗаписьАвторизована(НастройкиПользователя, ДатаСеанса);
		
		Если НЕ ЕстьАвторизация И ТипОперации = "Шифрование" Тогда
			КонтекстФормы.ТекущийЭлемент = ЭлементыФормы[ПолучитьИмяЭлементаФормы(ИменаЭлементов, "ПодтверждениеПароль")];
		КонецЕсли;
		
	ИначеЕсли (БылЭтап = "Выбор" ИЛИ БылЭтап = "Начало") Тогда
		Если ДанныеПодтверждения.ЭтапЦикла = "ВводКода" Тогда
			ОбновитьРазмерыФормы(КонтекстФормы);
			Если ЭлементыФормы[ПолучитьИмяЭлементаФормы(ИменаЭлементов, "ПодтверждениеКодПодтверждения")].Видимость Тогда
				КонтекстФормы.ТекущийЭлемент = ЭлементыФормы[ПолучитьИмяЭлементаФормы(ИменаЭлементов, "ПодтверждениеКодПодтверждения")];
			КонецЕсли;
		КонецЕсли;	

	КонецЕсли;
		
КонецПроцедуры

// Служебная для обработки элементов формы, формирует подсказку для выбранного способа подтверждения
//
// Параметры:
//  КонтекстФормы   			- ФормаКлиентскогоПриложения - содержит реквизиты:
//    * ДанныеПодтверждения	- см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//    * НастройкиПользователя	- см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//  ИмяЭлемента					- Строка
//
Процедура СформироватьПодсказкуСпособовВыбора(КонтекстФормы, ИмяЭлемента = "ПодтверждениеСпособПодтверждения")
	
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	ИменаЭлементов = РеестрИмен.ИменаЭлементовФормы;

	ЭлементФормы = КонтекстФормы.Элементы[ПолучитьИмяЭлементаФормы(ИменаЭлементов, ИмяЭлемента)];
	ДанныеПодтверждения = КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
	НастройкиПользователя = ПолучитьНастройкиПользователяИзФормы(КонтекстФормы, РеестрИмен);
	СписокВыбора = ЭлементФормы.СписокВыбора;
	
	КодЯзыка = ДанныеПодтверждения.КодЯзыка;
	ОбщаяСтрока = "";
	СпособОтображения = ОтображениеПодсказки.ОтображатьСнизу;
	
	Если СписокВыбора.Количество() = 0 Тогда
		ОбщаяСтрока = НСтр("ru = 'Пользователю не назначен ни один способ подтверждения.'", КодЯзыка);
		
	ИначеЕсли НЕ ЗначениеЗаполнено(ДанныеПодтверждения.ВторичнаяАвторизация) Тогда
		ОбщаяСтрока = НСтр("ru = 'Для продолжения укажите способ подтверждения'", КодЯзыка);

	ИначеЕсли ЗначениеЗаполнено(НастройкиПользователя.Ссылка) Тогда
		СпособОтображения = ОтображениеПодсказки.Кнопка;
		ПерваяЧасть = НСтр("ru = 'Можно изменить настройки подтверждения в'", КодЯзыка);
		ВтораяЧасть = НСтр("ru = 'карточке'", КодЯзыка);
		ТретьяЧасть = НСтр("ru = 'учетной записи'", КодЯзыка);
		
		ОбщаяСтрока = ?(ПустаяСтрока(ОбщаяСтрока), ОбщаяСтрока, ОбщаяСтрока + Символы.ПС) 
		+ ПерваяЧасть + " " 
		+ "<a href = """ + ПолучитьНавигационнуюСсылку(НастройкиПользователя.Ссылка) + """"
		+ ">" + ВтораяЧасть + "</a> " + ТретьяЧасть + "
		|<span style=""color: ПоясняющийТекст; font: МелкийЗаголовокПодтвержденияШрифт""> </span>";
		
	Иначе
		СпособОтображения = ОтображениеПодсказки.Нет;
		
	КонецЕсли;
	
	Результат = СтроковыеФункцииКлиент.ФорматированнаяСтрока(ОбщаяСтрока);
	ЭлементФормы.РасширеннаяПодсказка.Заголовок = Результат;
	ЭлементФормы.ОтображениеПодсказки = СпособОтображения;
	
КонецПроцедуры

// Служебная для обработки элементов формы, формирует заголовок оставшегося времени
//
Функция ПодтверждениеОтобразитьОсталось(ДанныеПодтверждения, ТекущийЗаголовок)
	
	ДатаСеанса = СервисКриптографииDSSСлужебныйКлиент.ДатаСеанса();
	Разница = 0;
	Если ЗначениеЗаполнено(ДанныеПодтверждения.СрокДействия) Тогда
		Разница = ДанныеПодтверждения.СрокДействия - ДатаСеанса;
	КонецЕсли;
	
	Если Разница > 0 Тогда
		Осталось = РазницаФормат(Разница, Истина);
	ИначеЕсли НЕ ЗначениеЗаполнено(ДанныеПодтверждения.СрокДействия) Тогда
		Осталось = "";
	КонецЕсли;
	
	Позиция = СтрНайти(ТекущийЗаголовок, "(");
	Если Позиция > 0 Тогда
		Результат = СокрЛП(Сред(ТекущийЗаголовок, 1, Позиция - 1)) + " " + Осталось;
	Иначе
		Результат = СокрЛП(ТекущийЗаголовок) + " " + Осталось;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Служебная для обработки элементов формы, меняет видимость групп формы со встроенным подтверждением
//
Процедура ИзменитьВидимостьКонтейнеров(СписокГрупп, ЭлементыФормы, ТекущийСтатус = Ложь)
	
	ВиднаГруппа = Ложь;
	
	Для каждого СтрокаКлюча Из СписокГрупп Цикл
		Если СтрокаКлюча.Ключ = "ГруппаСертификата" Тогда
			Продолжить;
		КонецЕсли;
		
		НашлиЭлемент = НайтиЭлементФормы(ЭлементыФормы, СтрокаКлюча.Значение);
		Если НЕ НашлиЭлемент Тогда
			Продолжить;
		КонецЕсли;
		
		ТекущийЭлемент = ЭлементыФормы[СтрокаКлюча.Значение];
		
		Если ТекущийСтатус = "Проверка" Тогда
			Если НЕ ТекущийЭлемент.Видимость Тогда
				ВиднаГруппа = ВиднаГруппа ИЛИ ТекущийЭлемент.Видимость;
			КонецЕсли;	
		ИначеЕсли ТекущийСтатус = Неопределено Тогда
			ТекущийЭлемент.Видимость = НЕ ТекущийЭлемент.Видимость;
		Иначе	
			ТекущийЭлемент.Видимость = ТекущийСтатус;
		КонецЕсли;	
	КонецЦикла;	
	
	Если ТекущийСтатус = "Проверка" И НЕ ВиднаГруппа Тогда
		Для каждого СтрокаКлюча Из СписокГрупп Цикл
			Если СтрокаКлюча.Ключ = "ГруппаСертификата" Тогда
				Продолжить;
			КонецЕсли;
			
			НашлиЭлемент = НайтиЭлементФормы(ЭлементыФормы, СтрокаКлюча.Значение);
			Если НЕ НашлиЭлемент Тогда
				Продолжить;
			КонецЕсли;
		
			ТекущийЭлемент = ЭлементыФормы[СтрокаКлюча.Значение];
			ТекущийЭлемент.Видимость = Истина;
		КонецЦикла;	
	КонецЕсли;
	
КонецПроцедуры

// Служебная для обработки элементов формы, проверяет наличие элемента на форме
//
Функция НайтиЭлементФормы(ЭлементыФормы, ИмяЭлемента)
	
	Результат = Ложь;
	
	НашлиЭлемент = ЭлементыФормы.Найти(ИмяЭлемента);
	Если НашлиЭлемент <> Неопределено Тогда
		Результат = Истина;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Служебная для обработки элементов формы, меняет свойства элемента формы
//
Процедура УстановитьСвойствоЭлемента(ЭлементыФормы, ИмяЭлемента, СвойствоЭлемента, ЗначениеЭлемента, ИменаЭлементов = Неопределено)
	
	НовоеИмя = ПолучитьПолеСтруктуры(ИменаЭлементов, ИмяЭлемента, ИмяЭлемента);
	
	Если НайтиЭлементФормы(ЭлементыФормы, НовоеИмя) Тогда
		ЭлементыФормы[НовоеИмя][СвойствоЭлемента] = ЗначениеЭлемента;
	КонецЕсли;
	
КонецПроцедуры

// Служебная для обработки элементов формы, адаптированная для элементов формы подписания
//
// Параметры:
//  ЭлементыФормы  	- ФормаКлиентскогоПриложения
//  НеНачалось		- Булево
//  НуженПинКод		- Булево
//  ПроверенПинКод	- Булево
//  СтандартныйВид	- Булево
//
Процедура УправлениеЭлементамиДляПодписания(ЭлементыФормы, НеНачалось, НуженПинКод, ПроверенПинКод = Ложь, СтандартныйВид = Ложь)
	
	КодЯзыка = СервисКриптографииDSSСлужебныйКлиент.КодЯзыка();
	
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПароль", "Видимость", НуженПинКод ИЛИ СтандартныйВид);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "Пароль", "ТолькоПросмотр", ПроверенПинКод);
	Если СтандартныйВид Тогда
		УстановитьСвойствоЭлемента(ЭлементыФормы, "Подписать", "КнопкаПоУмолчанию", Истина);
		УстановитьСвойствоЭлемента(ЭлементыФормы, "Пароль", "ТолькоПросмотр", Ложь);
	Иначе
		УстановитьСвойствоЭлемента(ЭлементыФормы, "Страницы", "Видимость", Ложь);
	КонецЕсли;	
	УстановитьСвойствоЭлемента(ЭлементыФормы, "Подписать", "Видимость", НеНачалось ИЛИ СтандартныйВид);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "Пароль", "Заголовок", ?(НуженПинКод И НЕ СтандартныйВид, НСтр("ru = 'Пин-код'", КодЯзыка), НСтр("ru = 'Пароль'", КодЯзыка)));
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ЗапомнитьПароль", "Заголовок", 
								?(НуженПинКод И НЕ СтандартныйВид, 
								НСтр("ru = 'Запомнить пин-код'", КодЯзыка),
								НСтр("ru = 'Запомнить пароль'", КодЯзыка)));
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПодписание", "ОтображатьЗаголовок", СтандартныйВид);

КонецПроцедуры

// Служебная для обработки элементов формы, адаптированная для элементов формы расшифрования
//
// Параметры:
//  ЭлементыФормы  	- ФормаКлиентскогоПриложения
//  НеНачалось		- Булево
//  НуженПинКод		- Булево
//  ПроверенПинКод	- Булево
//  СтандартныйВид	- Булево
//
Процедура УправлениеЭлементамиДляРасшифрования(ЭлементыФормы, НеНачалось, НуженПинКод, ПроверенПинКод = Ложь, СтандартныйВид = Ложь)
	
	КодЯзыка = СервисКриптографииDSSСлужебныйКлиент.КодЯзыка();
	
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПароль", "Видимость", НуженПинКод ИЛИ СтандартныйВид);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "Пароль", "ТолькоПросмотр", ПроверенПинКод);

	Если СтандартныйВид Тогда
		УстановитьСвойствоЭлемента(ЭлементыФормы, "ФормаРасшифровать", "КнопкаПоУмолчанию", Истина);
		УстановитьСвойствоЭлемента(ЭлементыФормы, "Пароль", "ТолькоПросмотр", Ложь);
	Иначе
		УстановитьСвойствоЭлемента(ЭлементыФормы, "Страницы", "Видимость", Ложь);
	КонецЕсли;
		
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ФормаРасшифровать", "Видимость", НеНачалось ИЛИ СтандартныйВид);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "Пароль", "Заголовок", ?(НуженПинКод И НЕ СтандартныйВид, НСтр("ru = 'Пин-код'", КодЯзыка), НСтр("ru = 'Пароль'", КодЯзыка)));
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ЗапомнитьПароль", "Заголовок", ?(НуженПинКод И НЕ СтандартныйВид, НСтр("ru = 'Запомнить пин-код'", КодЯзыка), НСтр("ru = 'Запомнить пароль'", КодЯзыка)));
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаРасшифровка", "ОтображатьЗаголовок", СтандартныйВид);
	
КонецПроцедуры

// Служебная для обработки элементов формы, адаптированная для элементов формы проверки сертификата
//
// Параметры:
//  ЭлементыФормы  	- ФормаКлиентскогоПриложения
//  НеНачалось		- Булево
//  НуженПинКод		- Булево
//  ПроверенПинКод	- Булево
//  СтандартныйВид	- Булево
//
Процедура УправлениеЭлементамиДляПроверки(ЭлементыФормы, НеНачалось, НуженПинКод, ПроверенПинКод = Ложь, СтандартныйВид = Ложь)
	
	КодЯзыка = СервисКриптографииDSSСлужебныйКлиент.КодЯзыка();
	
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаВводаПароля", "Видимость", НуженПинКод ИЛИ СтандартныйВид);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "Пароль", "ТолькоПросмотр", ПроверенПинКод);

	Если СтандартныйВид Тогда
		УстановитьСвойствоЭлемента(ЭлементыФормы, "ФормаПроверить", "КнопкаПоУмолчанию", Истина);
		УстановитьСвойствоЭлемента(ЭлементыФормы, "Пароль", "ТолькоПросмотр", Ложь);
	Иначе
		УстановитьСвойствоЭлемента(ЭлементыФормы, "Страницы", "Видимость", Ложь);
	КонецЕсли;
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаВводаПароля", "ОтображатьЗаголовок", СтандартныйВид);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ФормаПроверить", "Видимость", НеНачалось ИЛИ СтандартныйВид);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "Пароль", "Заголовок", ?(НуженПинКод И НЕ СтандартныйВид, НСтр("ru = 'Пин-код'", КодЯзыка), НСтр("ru = 'Пароль'", КодЯзыка)));
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ЗапомнитьПароль", "Заголовок", ?(НуженПинКод И НЕ СтандартныйВид, 
								НСтр("ru = 'Запомнить пин-код'", КодЯзыка),
								НСтр("ru = 'Запомнить пароль'", КодЯзыка)));
	
КонецПроцедуры

// Служебная для обработки элементов формы, выбирает адаптированную процедуру управления элементами формы
//
Процедура УправлениеЭлементамиФормы(КонтекстФормы, СтандартныйВид, НеНачалось, НуженПинКод, ПроверенПинКод = Ложь)
	
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	ФормаИсточник = КонтекстФормы[РеестрИмен.ПодтверждениеТипОперации];
	ЭлементыФормы = КонтекстФормы.Элементы;
	
	Если ФормаИсточник = "Подписание" Тогда
		УправлениеЭлементамиДляПодписания(ЭлементыФормы, НеНачалось, НуженПинКод, ПроверенПинКод, СтандартныйВид);
	ИначеЕсли ФормаИсточник = "Расшифрование" Тогда
		УправлениеЭлементамиДляРасшифрования(ЭлементыФормы, НеНачалось, НуженПинКод, ПроверенПинКод, СтандартныйВид);
	ИначеЕсли ФормаИсточник = "Проверка" Тогда
		УправлениеЭлементамиДляПроверки(ЭлементыФормы, НеНачалось, НуженПинКод, ПроверенПинКод, СтандартныйВид);
	КонецЕсли;
	
КонецПроцедуры

// Служебная для обработки элементов формы, общая форма управления добавленными элементами формы встроенного подтверждения
//
Процедура УправлениеЭлементамиОбщее(КонтекстФормы, ОткудаВызов)
	
	РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	ИменаЭлементов = РеестрИмен.ИменаЭлементовФормы;

	СписокГрупп	= КонтекстФормы[РеестрИмен.ИменаГруппКонтейнера];
	ЭлементыФормы = КонтекстФормы.Элементы;
	ОблачныйСертификат = ЭтоОперацияОблачнойПодписи(КонтекстФормы);
	ФормаИсточник = КонтекстФормы[РеестрИмен.ПодтверждениеТипОперации];
	
	Если НЕ ОблачныйСертификат Тогда
		УправлениеЭлементамиФормы(КонтекстФормы, Истина, Ложь, Ложь, Ложь);
		ИзменитьВидимостьКонтейнеров(СписокГрупп, ЭлементыФормы, Ложь);
		УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеРазделитель1", "Видимость", Ложь, ИменаЭлементов);
		Возврат;
	КонецЕсли;
	
	НастройкиПользователя	= КонтекстФормы[РеестрИмен.НастройкиПользователя];
	Если ФормаИсточник = "Аутентификация" 
			И НастройкиПользователя.ПервичнаяАутентификация = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Первичный_ДвухФакторная") Тогда
		ОтдельнаяАвторизация= Ложь;
	Иначе		
		ОтдельнаяАвторизация= НастройкиПользователя.ПервичнаяАутентификация = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Первичный_КодАвторизации");
	КонецЕсли;								

	ИспользованиеВозможно	= СервисКриптографииDSSКлиент.ИспользоватьСервисОблачнойПодписи();
	ОперацияАутентификации	= ФормаИсточник = "Аутентификация";
	ДатаСеанса				= СервисКриптографииDSSСлужебныйКлиент.ДатаСеанса();
	КодЯзыка 				= СервисКриптографииDSSСлужебныйКлиент.КодЯзыка();
	ДанныеПодтверждения		= КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
	ОжидатьВыполнения		= КонтекстФормы[РеестрИмен.ОжидатьВыполнения];
	БылаАвторизация			= ДанныеПодтверждения.ПараметрыВариантаВстроенного.ЕстьАвторизация И ИспользованиеВозможно И ФормаИсточник <> "Проверка";
	ПинКодПроверен			= ДанныеПодтверждения.ПараметрыВариантаВстроенного.ПинКодПроверен;
	ПарольВПамяти			= ДанныеПодтверждения.ПараметрыВариантаВстроенного.ПарольВПамяти;
	СпособПодтверждения 	= ДанныеПодтверждения.ВторичнаяАвторизация;
	ЕстьАвторизация			= СервисКриптографииDSSКлиентСервер.УчетнаяЗаписьАвторизована(НастройкиПользователя, ДатаСеанса) ИЛИ ОперацияАутентификации;
	ЕстьКомментарий			= Ложь;
	НеНачалось 				= ДанныеПодтверждения.ЭтапЦикла = "Инициализация"
								ИЛИ (ДанныеПодтверждения.ЭтапЦикла = "Ошибка" И НЕ ОтдельнаяАвторизация И НЕ ЕстьАвторизация);
	НуженПинКод				= ?(ЗначениеЗаполнено(ДанныеПодтверждения.Сертификат), ДанныеПодтверждения.Сертификат.ТребуетсяПинКод, Истина);
	СертификатАвторизации	= НастройкиПользователя.СертификатАвторизации 
								ИЛИ НастройкиПользователя.ПервичнаяАутентификация <> ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Первичный_СертификатАвторизации");
					
	КлючДействия 			= КлючДействияОперации(ФормаИсточник, НастройкиПользователя, ДанныеПодтверждения);
	ТребуетсяПодтверждение 	= КлючДействия.Подтверждать;
	
	Если НайтиЭлементФормы(ЭлементыФормы, "Комментарий") Тогда
		ЕстьКомментарий = ЭлементыФормы.Комментарий.Видимость;
	Иначе
		ЕстьКомментарий = ФормаИсточник = "Проверка";
	КонецЕсли;
	
	ТипПодтверждения = СервисКриптографииDSSКлиентСервер.ПолучитьВторичнуюАвторизацию(СпособПодтверждения);
	Если НЕ ТребуетсяПодтверждение ИЛИ НЕ ИспользованиеВозможно Тогда
		ВариантВидимости = 0;
	ИначеЕсли СервисКриптографииDSSКлиентСервер.ЭтоМобильноеПриложениеДляПодтверждения(СпособПодтверждения) Тогда
		ВариантВидимости = 3;
	ИначеЕсли ТипПодтверждения = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_СМС")
		ИЛИ ТипПодтверждения = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ЭлектроннаяПочта") Тогда
		ВариантВидимости = 1;
	ИначеЕсли ТипПодтверждения = ПредопределенноеЗначение("Перечисление.СпособыАвторизацииDSS.Вторичный_ОфлайнПодтверждение") Тогда
		ВариантВидимости = 2;
	Иначе
		ВариантВидимости = 4;
	КонецЕсли;
	
	ЭтапыПодтверждения = Новый Массив;
	ЭтапыПодтверждения.Добавить((БылаАвторизация ИЛИ ВариантВидимости <> 0) И НуженПинКод И НЕ ПарольВПамяти);
	ЭтапыПодтверждения.Добавить(БылаАвторизация);
	ЭтапыПодтверждения.Добавить(ТребуетсяПодтверждение);
	
	УправлениеЭлементамиФормы(КонтекстФормы, Ложь, НеНачалось И (НЕ ОтдельнаяАвторизация ИЛИ ЕстьАвторизация), НуженПинКод И ИспользованиеВозможно, ПинКодПроверен);
	
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеРазделитель1", "Видимость", ЭтапыПодтверждения[0], ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеРазделитель2", "Видимость", ЭтапыПодтверждения[1], ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеРазделитель3", "Видимость", ИспользованиеВозможно И (ВариантВидимости <> 0 ИЛИ БылаАвторизация), ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеРазделитель4", "Видимость", ЕстьКомментарий И (ВариантВидимости <> 0 ИЛИ БылаАвторизация), ИменаЭлементов);
	
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПодтвержденияУчетнаяЗапись", "Видимость", НЕ ОтдельнаяАвторизация И БылаАвторизация, ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеЛогин", "Видимость", ЗначениеЗаполнено(КонтекстФормы[РеестрИмен.Логин]), ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПодтверждениеПарольЗапомнить", "Видимость", НЕ ОтдельнаяАвторизация И БылаАвторизация, ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеЗапомнитьПарольЛогина", "Видимость", ЗначениеЗаполнено(КонтекстФормы[РеестрИмен.Логин]), ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПодтвержденияУчетнаяЗаписьВеб", "Видимость", ОтдельнаяАвторизация И БылаАвторизация, ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеПредставлениеСертификата", "Видимость", НЕ ОтдельнаяАвторизация И БылаАвторизация И НЕ СертификатАвторизации, ИменаЭлементов);
	
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПодтвержденияКод", "Видимость", НЕ НеНачалось И (ЕстьАвторизация ИЛИ ОперацияАутентификации) И (ВариантВидимости = 1 ИЛИ ВариантВидимости = 2), ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеПовторить", "Видимость", НЕ НеНачалось И ВариантВидимости = 1, ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПодтвержденияОфлайн", "Видимость", НЕ НеНачалось И (ЕстьАвторизация ИЛИ ОперацияАутентификации) И ВариантВидимости = 2, ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПодтвержденияВыбор", "Видимость", ВариантВидимости <> 0, ИменаЭлементов);
	Если БылаАвторизация И ИспользованиеВозможно Тогда
		УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПодтвержденияВыбор", "Доступность", ВариантВидимости <> 0, ИменаЭлементов);
	КонецЕсли;	
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПодтвержденияОписание", "Видимость", НЕ НеНачалось И (ЕстьАвторизация ИЛИ ОперацияАутентификации), ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПодтвержденияОнлайн", "Видимость", НЕ НеНачалось И (ЕстьАвторизация ИЛИ ОперацияАутентификации) И ВариантВидимости = 3, ИменаЭлементов);
	
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеПредставлениеСертификата", "ТолькоПросмотр", ЕстьАвторизация ИЛИ (ОперацияАутентификации И НЕ НеНачалось), ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеПароль", "ТолькоПросмотр", ЕстьАвторизация И НЕ ОперацияАутентификации, ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ГруппаПодтвержденияУчетнаяЗаписьВеб", "ТолькоПросмотр", ЕстьАвторизация, ИменаЭлементов);
	
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеОК", "КнопкаПоУмолчанию", НЕ НеНачалось, ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеОК", "Доступность", НЕ НеНачалось И НЕ ОжидатьВыполнения, ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеИнструкция", "Видимость", НЕ НеНачалось И ВариантВидимости = 2, ИменаЭлементов);
	
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеПовторить", "Доступность", НЕ НеНачалось И НЕ ОжидатьВыполнения, ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеКодПодтверждения", "Доступность", НЕ НеНачалось И НЕ ОжидатьВыполнения, ИменаЭлементов);
	УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеСпособПодтверждения", "Доступность", ВариантВидимости <> 0, ИменаЭлементов);
	Если ОтдельнаяАвторизация Тогда
		УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеАвторизацияВеб", "Доступность", БылаАвторизация И НЕ ЕстьАвторизация, ИменаЭлементов);
		УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеАвторизацияВеб", "Заголовок", 
				?(НЕ ЕстьАвторизация, НСтр("ru = 'авторизоваться'", КодЯзыка), НСтр("ru = 'авторизован'", КодЯзыка)), ИменаЭлементов);
	КонецЕсли;
	
	Если ВариантВидимости = 1 Тогда
		УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеКодПодтверждения", "Заголовок", НСтр("ru = 'Одноразовый пароль'", КодЯзыка), ИменаЭлементов);
	ИначеЕсли ВариантВидимости = 2 Тогда
		УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеКодПодтверждения", "Заголовок", НСтр("ru = 'Код'", КодЯзыка), ИменаЭлементов);
	КонецЕсли;
	
	// нумеруем этапы
	ВсегоЭтапов = 0;
	Для Счетчик = 1 По ЭтапыПодтверждения.Количество() Цикл
		Если ЭтапыПодтверждения[Счетчик - 1] Тогда
			ВсегоЭтапов = ВсегоЭтапов + 1;
		КонецЕсли;
	КонецЦикла;	

	Всего = 1;
	Для Счетчик = 1 По ЭтапыПодтверждения.Количество() Цикл
		Если ЭтапыПодтверждения[Счетчик - 1] И ВсегоЭтапов > 1 Тогда
			ЗначениеШага = Всего;
			Всего = Всего + 1;
		Иначе
			ЗначениеШага = -1;
		КонецЕсли;
		ИмяЗначения = РеестрИмен["ПодтверждениеШаг" + Счетчик];
		КонтекстФормы[ИмяЗначения] = ЗначениеШага;
		УстановитьСвойствоЭлемента(ЭлементыФормы, "ПодтверждениеРазделитель" + Счетчик + "Номер", "Видимость", ЗначениеШага > 0, ИменаЭлементов);
	КонецЦикла;
	
	ИзменитьВидимостьКонтейнеров(СписокГрупп, ЭлементыФормы, "Проверка");
	
КонецПроцедуры

// Обертка для упрощения вызова основной функции
//
Функция ПолучитьПолеСтруктуры(ДанныеСтруктуры, Знач ПутьДанных, ЗначениеПоУмолчанию = Неопределено, УчитыватьРегистр = Ложь)
	
	Возврат СервисКриптографииDSSКлиентСервер.ПолучитьПолеСтруктуры(ДанныеСтруктуры, ПутьДанных, ЗначениеПоУмолчанию, УчитыватьРегистр);
	
КонецФункции

Функция ИмяБазовогоРеквизита()
	
	Возврат "DSS_НаборРеквизитовФормы";
	
КонецФункции

Функция ПолучитьИмяЭлементаФормы(ИменаЭлементов, ТекущееИмя)
	
	Результат = ПолучитьПолеСтруктуры(ИменаЭлементов, ТекущееИмя, ТекущееИмя);
	
	Возврат Результат;
	
КонецФункции

// Получает значение настроек подключения к сервису из формы
// 
// Параметры:
//  ЭлементыФормы	- ФормаКлиентскогоПриложения
//  РеестрИмен		- Структура
//            		- Неопределено
//
// Возвращаемое значение:
//   см. СервисКриптографииDSS.НастройкиПользователяПоУмолчанию
//
Функция ПолучитьНастройкиПользователяИзФормы(КонтекстФормы, РеестрИмен = Неопределено)
	
	Если РеестрИмен = Неопределено Тогда
		РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	КонецЕсли;
	
	Результат = КонтекстФормы[РеестрИмен.НастройкиПользователя];
	
	Возврат Результат;
	
КонецФункции

// Получает значение данных сертификата при работе с сервисом из формы
// 
// Параметры:
//  ЭлементыФормы	- ФормаКлиентскогоПриложения
//  РеестрИмен		- Структура
//            		- Неопределено
//
// Возвращаемое значение:
//   Структура:
//     * Идентификатор - Строка
//
Функция ПолучитьДанныеСертификатаИзФормы(КонтекстФормы, РеестрИмен = Неопределено)
	
	Если РеестрИмен = Неопределено Тогда
		РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	КонецЕсли;
	
	Результат = КонтекстФормы[РеестрИмен.ДанныеСертификата];
	
	Возврат Результат;
	
КонецФункции

// Получает значение данных подтверждения при работе с сервисом из формы
// 
// Параметры:
//  ЭлементыФормы	- ФормаКлиентскогоПриложения
//  РеестрИмен		- Структура
//            		- Неопределено
//
// Возвращаемое значение:
//   см. СервисКриптографииDSSПодтверждениеСервер.ДанныеВторичнойАвторизацииПоУмолчанию
//
Функция ДанныеПодтвержденияИзФормы(КонтекстФормы, РеестрИмен = Неопределено)
	
	Если РеестрИмен = Неопределено Тогда
		РеестрИмен = БазовыйРеестрРеквизитов(КонтекстФормы);
	КонецЕсли;
	
	Результат = КонтекстФормы[РеестрИмен.ДанныеПодтверждения];
	Возврат Результат;
	
КонецФункции

#КонецОбласти
